diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index df848cc7f..8e64ce6b9 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -11,26 +11,29 @@ configurations { } dependencies { - compile 'com.google.firebase:firebase-messaging:17.1.0' - compile 'com.google.firebase:firebase-config:16.0.0' - compile 'com.google.android.gms:play-services-maps:15.0.1' - compile 'com.google.android.gms:play-services-vision:15.0.2' - compile 'com.google.android.gms:play-services-wallet:15.0.1' - compile 'com.google.android.gms:play-services-wearable:15.0.1' - implementation 'com.android.support:support-core-ui:27.1.1' - implementation 'com.android.support:support-compat:27.1.1' - implementation 'com.android.support:support-core-utils:27.1.1' - implementation 'com.android.support:support-v13:27.1.1' - implementation 'com.android.support:palette-v7:27.1.1' - implementation 'com.android.support:exifinterface:27.1.1' - compile 'net.hockeyapp.android:HockeySDK:5.1.0' - compile 'com.googlecode.mp4parser:isoparser:1.0.6' - compile 'com.stripe:stripe-android:2.0.2' + compileOnly 'org.checkerframework:checker-qual:2.5.0' + compileOnly 'org.checkerframework:checker-compat-qual:2.5.0' + implementation 'com.google.firebase:firebase-core:16.0.3' + implementation 'com.google.firebase:firebase-messaging:17.3.0' + implementation 'com.google.firebase:firebase-config:16.0.0' + implementation 'com.google.android.gms:play-services-maps:15.0.1' + implementation 'com.google.android.gms:play-services-vision:15.0.2' + implementation 'com.google.android.gms:play-services-wallet:16.0.0' + implementation 'com.google.android.gms:play-services-wearable:15.0.1' + implementation 'com.android.support:support-core-ui:28.0.0-rc01' + implementation 'com.android.support:support-compat:28.0.0-rc01' + implementation 'com.android.support:support-core-utils:28.0.0-rc01' + implementation 'com.android.support:support-v13:28.0.0-rc01' + implementation 'com.android.support:palette-v7:28.0.0-rc01' + implementation 'com.android.support:exifinterface:28.0.0-rc01' + implementation 'net.hockeyapp.android:HockeySDK:5.1.0' + implementation 'com.googlecode.mp4parser:isoparser:1.0.6' + implementation 'com.stripe:stripe-android:2.0.2' } android { - compileSdkVersion 27 - buildToolsVersion '27.0.3' + compileSdkVersion 28 + buildToolsVersion '28.0.2' defaultConfig.applicationId = "org.telegram.messenger" @@ -52,8 +55,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } signingConfigs { @@ -98,7 +101,7 @@ android { } } - defaultConfig.versionCode = 1340 + defaultConfig.versionCode = 1358 sourceSets.debug { manifest.srcFile 'config/debug/AndroidManifest.xml' @@ -235,7 +238,7 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 27 - versionName "4.9.0" + versionName "4.9.1" vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] diff --git a/TMessagesProj/jni/Android.mk b/TMessagesProj/jni/Android.mk index f9f3b4bac..6542a9dfd 100755 --- a/TMessagesProj/jni/Android.mk +++ b/TMessagesProj/jni/Android.mk @@ -387,7 +387,7 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false -LOCAL_MODULE := tmessages.28 +LOCAL_MODULE := tmessages.29 LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 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 diff --git a/TMessagesProj/jni/SqliteWrapper.cpp b/TMessagesProj/jni/SqliteWrapper.cpp index 51d758aaa..13c9e57ce 100755 --- a/TMessagesProj/jni/SqliteWrapper.cpp +++ b/TMessagesProj/jni/SqliteWrapper.cpp @@ -142,10 +142,12 @@ jlong Java_org_telegram_SQLite_SQLiteDatabase_opendb(JNIEnv *env, jobject object char const *fileNameStr = env->GetStringUTFChars(fileName, 0); char const *tempDirStr = env->GetStringUTFChars(tempDir, 0); - if (sqlite3_temp_directory != 0) { + if (sqlite3_temp_directory != 0 && strcmp(sqlite3_temp_directory, tempDirStr)) { sqlite3_free(sqlite3_temp_directory); } - sqlite3_temp_directory = sqlite3_mprintf("%s", tempDirStr); + if (sqlite3_temp_directory == 0) { + sqlite3_temp_directory = sqlite3_mprintf("%s", tempDirStr); + } sqlite3 *handle = 0; int err = sqlite3_open(fileNameStr, &handle); diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp index a656dbeaf..da84f81e0 100644 --- a/TMessagesProj/jni/TgNetWrapper.cpp +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -39,6 +39,8 @@ jmethodID jclass_ConnectionsManager_onProxyError; jmethodID jclass_ConnectionsManager_getHostByName; jmethodID jclass_ConnectionsManager_getInitFlags; +bool check_utf8(const char *data, size_t len); + /*jint createLoadOpetation(JNIEnv *env, jclass c, jint dc_id, jlong id, jlong volume_id, jlong access_hash, jint local_id, jbyteArray encKey, jbyteArray encIv, jstring extension, jint version, jint size, jstring dest, jstring temp, jobject delegate) { if (encKey != nullptr && encIv == nullptr || encKey == nullptr && encIv != nullptr || extension == nullptr || dest == nullptr || temp == nullptr) { return 0; @@ -196,7 +198,13 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject ptr = (jlong) resp->response.get(); } else if (error != nullptr) { errorCode = error->code; - errorText = jniEnv[instanceNum]->NewStringUTF(error->text.c_str()); + const char *text = error->text.c_str(); + size_t size = error->text.size(); + if (check_utf8(text, size)) { + errorText = jniEnv[instanceNum]->NewStringUTF(text); + } else { + errorText = jniEnv[instanceNum]->NewStringUTF("UTF-8 ERROR"); + } } if (onComplete != nullptr) { jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText, networkType); @@ -632,3 +640,56 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) { return JNI_TRUE; } + +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +bool check_utf8(const char *data, size_t len) { + const char *data_end = data + len; + do { + unsigned int a = (unsigned char) (*data++); + if ((a & 0x80) == 0) { + if (data == data_end + 1) { + return true; + } + continue; + } + +#define ENSURE(condition) \ +if (!(condition)) { \ + return false; \ +} + + ENSURE((a & 0x40) != 0); + + unsigned int b = (unsigned char) (*data++); + ENSURE((b & 0xc0) == 0x80); + if ((a & 0x20) == 0) { + ENSURE((a & 0x1e) > 0); + continue; + } + + unsigned int c = (unsigned char) (*data++); + ENSURE((c & 0xc0) == 0x80); + if ((a & 0x10) == 0) { + int x = (((a & 0x0f) << 6) | (b & 0x20)); + ENSURE(x != 0 && x != 0x360); + continue; + } + + unsigned int d = (unsigned char) (*data++); + ENSURE((d & 0xc0) == 0x80); + if ((a & 0x08) == 0) { + int t = (((a & 0x07) << 6) | (b & 0x30)); + ENSURE(0 < t && t < 0x110); + continue; + } + + return false; +#undef ENSURE + } while (1); +} diff --git a/TMessagesProj/jni/exoplayer/ffmpeg_jni.cc b/TMessagesProj/jni/exoplayer/ffmpeg_jni.cc index 9adf6c457..d459712f4 100755 --- a/TMessagesProj/jni/exoplayer/ffmpeg_jni.cc +++ b/TMessagesProj/jni/exoplayer/ffmpeg_jni.cc @@ -36,10 +36,10 @@ extern "C" { __VA_ARGS__)) #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ - JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_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, ...) \ - JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) + JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) #define ERROR_STRING_BUFFER_LENGTH 256 @@ -60,8 +60,9 @@ AVCodec *getCodecByName(JNIEnv* env, jstring codecName); * provided extraData as initialization data for the decoder if it is non-NULL. * Returns the created context. */ -AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, - jbyteArray extraData, jboolean outputFloat); +AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData, + jboolean outputFloat, jint rawSampleRate, + jint rawChannelCount); /** * Decodes the packet into the output buffer, returning the number of bytes @@ -89,13 +90,14 @@ LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) { } DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData, - jboolean outputFloat) { + jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) { AVCodec *codec = getCodecByName(env, codecName); if (!codec) { LOGE("Codec not found."); return 0L; } - return (jlong) createContext(env, codec, extraData, outputFloat); + return (jlong)createContext(env, codec, extraData, outputFloat, rawSampleRate, + rawChannelCount); } DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData, @@ -159,8 +161,11 @@ DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) { LOGE("Unexpected error finding codec %d.", codecId); return 0L; } - return (jlong) createContext(env, codec, extraData, - context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT); + jboolean outputFloat = + (jboolean)(context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT); + return (jlong)createContext(env, codec, extraData, outputFloat, + /* rawSampleRate= */ -1, + /* rawChannelCount= */ -1); } avcodec_flush_buffers(context); @@ -173,7 +178,7 @@ DECODER_FUNC(void, ffmpegRelease, jlong context) { } } -AVCodec *getCodecByName(JNIEnv *env, jstring codecName) { +AVCodec *getCodecByName(JNIEnv* env, jstring codecName) { if (!codecName) { return NULL; } @@ -183,8 +188,9 @@ AVCodec *getCodecByName(JNIEnv *env, jstring codecName) { return codec; } -AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, - jbyteArray extraData, jboolean outputFloat) { +AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData, + jboolean outputFloat, jint rawSampleRate, + jint rawChannelCount) { AVCodecContext *context = avcodec_alloc_context3(codec); if (!context) { LOGE("Failed to allocate context."); @@ -204,6 +210,12 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, } env->GetByteArrayRegion(extraData, 0, size, (jbyte *) context->extradata); } + if (context->codec_id == AV_CODEC_ID_PCM_MULAW || + context->codec_id == AV_CODEC_ID_PCM_ALAW) { + context->sample_rate = rawSampleRate; + context->channels = rawChannelCount; + context->channel_layout = av_get_default_channel_layout(rawChannelCount); + } int result = avcodec_open2(context, codec, NULL); if (result < 0) { logError("avcodec_open2", result); @@ -244,7 +256,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet, // Resample output. AVSampleFormat sampleFormat = context->sample_fmt; int channelCount = context->channels; - uint64_t channelLayout = context->channel_layout; + int channelLayout = context->channel_layout; int sampleRate = context->sample_rate; int sampleCount = frame->nb_samples; int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount, @@ -254,7 +266,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet, resampleContext = (AVAudioResampleContext *) context->opaque; } else { resampleContext = avresample_alloc_context(); - 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, "in_sample_rate", sampleRate, 0); av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0); diff --git a/TMessagesProj/jni/exoplayer/flac_jni.cc b/TMessagesProj/jni/exoplayer/flac_jni.cc index 40f5875da..3b47751b8 100755 --- a/TMessagesProj/jni/exoplayer/flac_jni.cc +++ b/TMessagesProj/jni/exoplayer/flac_jni.cc @@ -19,150 +19,152 @@ #include "include/flac_parser.h" #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ -RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_flac_FlacDecoderJni_##NAME(JNIEnv *env, jobject thiz, ##__VA_ARGS__) +RETURN_TYPE Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME(JNIEnv *env, jobject thiz, ##__VA_ARGS__) class JavaDataSource : public DataSource { - public: - void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) { - this->env = env; - this->flacDecoderJni = flacDecoderJni; - if (mid == NULL) { - jclass cls = env->GetObjectClass(flacDecoderJni); - mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I"); - env->DeleteLocalRef(cls); +public: + void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) { + this->env = env; + this->flacDecoderJni = flacDecoderJni; + if (mid == NULL) { + jclass cls = env->GetObjectClass(this->flacDecoderJni); + mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I"); + env->DeleteLocalRef(cls); + } } - } - ssize_t readAt(off64_t offset, void *const data, size_t size) { - jobject byteBuffer = env->NewDirectByteBuffer(data, size); - int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer); - if (env->ExceptionCheck()) { - // Exception is thrown in Java when returning from the native call. - result = -1; + ssize_t readAt(off64_t offset, void *const data, size_t size) { + jobject byteBuffer = env->NewDirectByteBuffer(data, size); + int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer); + if (env->ExceptionCheck()) { + // Exception is thrown in Java when returning from the native call. + result = -1; + } + env->DeleteLocalRef(byteBuffer); + return result; } - env->DeleteLocalRef(byteBuffer); - return result; - } - private: - JNIEnv *env; - jobject flacDecoderJni; - jmethodID mid; +private: + JNIEnv *env; + jobject flacDecoderJni; + jmethodID mid; }; struct Context { - JavaDataSource *source; - FLACParser *parser; + JavaDataSource *source; + FLACParser *parser; - Context() { - source = new JavaDataSource(); - parser = new FLACParser(source); - } + Context() { + source = new JavaDataSource(); + parser = new FLACParser(source); + } - ~Context() { - delete parser; - delete source; - } + ~Context() { + delete parser; + delete source; + } }; extern "C" { DECODER_FUNC(jlong, flacInit) { - Context *context = new Context; - if (!context->parser->init()) { - delete context; - return 0; - } - return reinterpret_cast(context); + Context *context = new Context; + if (!context->parser->init()) { + delete context; + return 0; + } + return reinterpret_cast(context); } DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) { - Context *context = reinterpret_cast(jContext); - context->source->setFlacDecoderJni(env, thiz); - if (!context->parser->decodeMetadata()) { - return NULL; - } + Context *context = reinterpret_cast(jContext); + context->source->setFlacDecoderJni(env, thiz); + if (!context->parser->decodeMetadata()) { + return NULL; + } - const FLAC__StreamMetadata_StreamInfo &streamInfo = - context->parser->getStreamInfo(); + const FLAC__StreamMetadata_StreamInfo &streamInfo = + context->parser->getStreamInfo(); - jclass cls = env->FindClass("org/telegram/messenger/exoplayer2/util/FlacStreamInfo"); - jmethodID constructor = env->GetMethodID(cls, "", "(IIIIIIIJ)V"); + jclass cls = env->FindClass( + "com/google/android/exoplayer2/util/" + "FlacStreamInfo"); + jmethodID constructor = env->GetMethodID(cls, "", "(IIIIIIIJ)V"); - return env->NewObject(cls, constructor, streamInfo.min_blocksize, - streamInfo.max_blocksize, streamInfo.min_framesize, - streamInfo.max_framesize, streamInfo.sample_rate, - streamInfo.channels, streamInfo.bits_per_sample, - streamInfo.total_samples); + return env->NewObject(cls, constructor, streamInfo.min_blocksize, + streamInfo.max_blocksize, streamInfo.min_framesize, + streamInfo.max_framesize, streamInfo.sample_rate, + streamInfo.channels, streamInfo.bits_per_sample, + streamInfo.total_samples); } DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) { - Context *context = reinterpret_cast(jContext); - context->source->setFlacDecoderJni(env, thiz); - void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer); - jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer); - return context->parser->readBuffer(outputBuffer, outputSize); + Context *context = reinterpret_cast(jContext); + context->source->setFlacDecoderJni(env, thiz); + void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer); + jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer); + return context->parser->readBuffer(outputBuffer, outputSize); } DECODER_FUNC(jint, flacDecodeToArray, jlong jContext, jbyteArray jOutputArray) { - Context *context = reinterpret_cast(jContext); - context->source->setFlacDecoderJni(env, thiz); - jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL); - jint outputSize = env->GetArrayLength(jOutputArray); - int count = context->parser->readBuffer(outputBuffer, outputSize); - env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0); - return count; + Context *context = reinterpret_cast(jContext); + context->source->setFlacDecoderJni(env, thiz); + jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL); + jint outputSize = env->GetArrayLength(jOutputArray); + int count = context->parser->readBuffer(outputBuffer, outputSize); + env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0); + return count; } DECODER_FUNC(jlong, flacGetDecodePosition, jlong jContext) { - Context *context = reinterpret_cast(jContext); - return context->parser->getDecodePosition(); + Context *context = reinterpret_cast(jContext); + return context->parser->getDecodePosition(); } DECODER_FUNC(jlong, flacGetLastFrameTimestamp, jlong jContext) { - Context *context = reinterpret_cast(jContext); - return context->parser->getLastFrameTimestamp(); + Context *context = reinterpret_cast(jContext); + return context->parser->getLastFrameTimestamp(); } DECODER_FUNC(jlong, flacGetLastFrameFirstSampleIndex, jlong jContext) { - Context *context = reinterpret_cast(jContext); - return context->parser->getLastFrameFirstSampleIndex(); + Context *context = reinterpret_cast(jContext); + return context->parser->getLastFrameFirstSampleIndex(); } DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) { - Context *context = reinterpret_cast(jContext); - return context->parser->getNextFrameFirstSampleIndex(); + Context *context = reinterpret_cast(jContext); + return context->parser->getNextFrameFirstSampleIndex(); } DECODER_FUNC(jlong, flacGetSeekPosition, jlong jContext, jlong timeUs) { - Context *context = reinterpret_cast(jContext); - return context->parser->getSeekPosition(timeUs); + Context *context = reinterpret_cast(jContext); + return context->parser->getSeekPosition(timeUs); } DECODER_FUNC(jstring, flacGetStateString, jlong jContext) { - Context *context = reinterpret_cast(jContext); - const char *str = context->parser->getDecoderStateString(); - return env->NewStringUTF(str); + Context *context = reinterpret_cast(jContext); + const char *str = context->parser->getDecoderStateString(); + return env->NewStringUTF(str); } DECODER_FUNC(jboolean, flacIsDecoderAtEndOfStream, jlong jContext) { - Context *context = reinterpret_cast(jContext); - return context->parser->isDecoderAtEndOfStream(); + Context *context = reinterpret_cast(jContext); + return context->parser->isDecoderAtEndOfStream(); } DECODER_FUNC(void, flacFlush, jlong jContext) { - Context *context = reinterpret_cast(jContext); - context->parser->flush(); + Context *context = reinterpret_cast(jContext); + context->parser->flush(); } DECODER_FUNC(void, flacReset, jlong jContext, jlong newPosition) { - Context *context = reinterpret_cast(jContext); - context->parser->reset(newPosition); + Context *context = reinterpret_cast(jContext); + context->parser->reset(newPosition); } DECODER_FUNC(void, flacRelease, jlong jContext) { - Context *context = reinterpret_cast(jContext); - delete context; + Context *context = reinterpret_cast(jContext); + delete context; } } diff --git a/TMessagesProj/jni/exoplayer/flac_parser.cc b/TMessagesProj/jni/exoplayer/flac_parser.cc index 83d336741..26deac263 100755 --- a/TMessagesProj/jni/exoplayer/flac_parser.cc +++ b/TMessagesProj/jni/exoplayer/flac_parser.cc @@ -52,31 +52,31 @@ const int endian = 1; // with the same parameter list, but discard redundant information. FLAC__StreamDecoderReadStatus FLACParser::read_callback( - const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[], - size_t *bytes, void *client_data) { + const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[], + size_t *bytes, void *client_data) { return reinterpret_cast(client_data) - ->readCallback(buffer, bytes); + ->readCallback(buffer, bytes); } FLAC__StreamDecoderSeekStatus FLACParser::seek_callback( - const FLAC__StreamDecoder * /* decoder */, - FLAC__uint64 absolute_byte_offset, void *client_data) { + const FLAC__StreamDecoder * /* decoder */, + FLAC__uint64 absolute_byte_offset, void *client_data) { return reinterpret_cast(client_data) - ->seekCallback(absolute_byte_offset); + ->seekCallback(absolute_byte_offset); } FLAC__StreamDecoderTellStatus FLACParser::tell_callback( - const FLAC__StreamDecoder * /* decoder */, - FLAC__uint64 *absolute_byte_offset, void *client_data) { + const FLAC__StreamDecoder * /* decoder */, + FLAC__uint64 *absolute_byte_offset, void *client_data) { return reinterpret_cast(client_data) - ->tellCallback(absolute_byte_offset); + ->tellCallback(absolute_byte_offset); } FLAC__StreamDecoderLengthStatus FLACParser::length_callback( - const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length, - void *client_data) { + const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length, + void *client_data) { return reinterpret_cast(client_data) - ->lengthCallback(stream_length); + ->lengthCallback(stream_length); } FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */, @@ -85,10 +85,10 @@ FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */, } FLAC__StreamDecoderWriteStatus FLACParser::write_callback( - const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame, - const FLAC__int32 *const buffer[], void *client_data) { + const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame, + const FLAC__int32 *const buffer[], void *client_data) { return reinterpret_cast(client_data) - ->writeCallback(frame, buffer); + ->writeCallback(frame, buffer); } void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */, @@ -125,27 +125,27 @@ FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[], } FLAC__StreamDecoderSeekStatus FLACParser::seekCallback( - FLAC__uint64 absolute_byte_offset) { + FLAC__uint64 absolute_byte_offset) { mCurrentPos = absolute_byte_offset; mEOF = false; return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } FLAC__StreamDecoderTellStatus FLACParser::tellCallback( - FLAC__uint64 *absolute_byte_offset) { + FLAC__uint64 *absolute_byte_offset) { *absolute_byte_offset = mCurrentPos; return FLAC__STREAM_DECODER_TELL_STATUS_OK; } FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback( - FLAC__uint64 *stream_length) { + FLAC__uint64 *stream_length) { return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; } FLAC__bool FLACParser::eofCallback() { return mEOF; } FLAC__StreamDecoderWriteStatus FLACParser::writeCallback( - const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { + const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { if (mWriteRequested) { mWriteRequested = false; // FLAC parser doesn't free or realloc buffer until next frame or finish @@ -168,13 +168,13 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) { } else { ALOGE("FLACParser::metadataCallback unexpected STREAMINFO"); } - break; + break; case FLAC__METADATA_TYPE_SEEKTABLE: mSeekTable = &metadata->data.seek_table; - break; + break; default: ALOGE("FLACParser::metadataCallback unexpected type %u", metadata->type); - break; + break; } } @@ -195,7 +195,7 @@ static void copyToByteArrayBigEndian(int8_t *dst, const int *const *src, // and then skip the first few bytes (most significant bytes) // depending on the bit depth const int8_t *byteSrc = - reinterpret_cast(&src[c][i]) + 4 - bytesPerSample; + reinterpret_cast(&src[c][i]) + 4 - bytesPerSample; memcpy(dst, byteSrc, bytesPerSample); dst = dst + bytesPerSample; } @@ -225,18 +225,18 @@ static void copyTrespass(int8_t * /* dst */, const int *const * /* src */, // FLACParser FLACParser::FLACParser(DataSource *source) - : mDataSource(source), - mCopy(copyTrespass), - mDecoder(NULL), - mSeekTable(NULL), - firstFrameOffset(0LL), - mCurrentPos(0LL), - mEOF(false), - mStreamInfoValid(false), - mWriteRequested(false), - mWriteCompleted(false), - mWriteBuffer(NULL), - mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) { + : mDataSource(source), + mCopy(copyTrespass), + mDecoder(NULL), + mSeekTable(NULL), + firstFrameOffset(0LL), + mCurrentPos(0LL), + mEOF(false), + mStreamInfoValid(false), + mWriteRequested(false), + mWriteCompleted(false), + mWriteBuffer(NULL), + mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) { ALOGV("FLACParser::FLACParser"); memset(&mStreamInfo, 0, sizeof(mStreamInfo)); memset(&mWriteHeader, 0, sizeof(mWriteHeader)); @@ -268,9 +268,9 @@ bool FLACParser::init() { FLAC__METADATA_TYPE_SEEKTABLE); FLAC__StreamDecoderInitStatus initStatus; initStatus = FLAC__stream_decoder_init_stream( - mDecoder, read_callback, seek_callback, tell_callback, length_callback, - eof_callback, write_callback, metadata_callback, error_callback, - reinterpret_cast(this)); + mDecoder, read_callback, seek_callback, tell_callback, length_callback, + eof_callback, write_callback, metadata_callback, error_callback, + reinterpret_cast(this)); if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { // A failure here probably indicates a programming error and so is // unlikely to happen. But we check and log here similarly to above. @@ -304,7 +304,7 @@ bool FLACParser::decodeMetadata() { break; default: ALOGE("unsupported bits per sample %u", getBitsPerSample()); - return false; + return false; } // check sample rate switch (getSampleRate()) { @@ -324,7 +324,7 @@ bool FLACParser::decodeMetadata() { break; default: ALOGE("unsupported sample rate %u", getSampleRate()); - return false; + return false; } // configure the appropriate copy function based on device endianness. if (isBigEndian()) { @@ -367,11 +367,11 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) { mWriteHeader.channels != getChannels() || mWriteHeader.bits_per_sample != getBitsPerSample()) { ALOGE( - "FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d " - "-> %d/%d/%d", - getSampleRate(), getChannels(), getBitsPerSample(), - mWriteHeader.sample_rate, mWriteHeader.channels, - mWriteHeader.bits_per_sample); + "FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d " + "-> %d/%d/%d", + getSampleRate(), getChannels(), getBitsPerSample(), + mWriteHeader.sample_rate, mWriteHeader.channels, + mWriteHeader.bits_per_sample); return -1; } @@ -379,9 +379,9 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) { size_t bufferSize = blocksize * getChannels() * bytesPerSample; if (bufferSize > output_size) { ALOGE( - "FLACParser::readBuffer not enough space in output buffer " - "%zu < %zu", - output_size, bufferSize); + "FLACParser::readBuffer not enough space in output buffer " + "%zu < %zu", + output_size, bufferSize); return -1; } @@ -402,7 +402,7 @@ int64_t FLACParser::getSeekPosition(int64_t timeUs) { int64_t sample = (timeUs * getSampleRate()) / 1000000LL; if (sample >= getTotalSamples()) { - sample = getTotalSamples(); + sample = getTotalSamples(); } FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points; diff --git a/TMessagesProj/jni/exoplayer/opus_jni.cc b/TMessagesProj/jni/exoplayer/opus_jni.cc index 64ceb9b75..dfa638919 100755 --- a/TMessagesProj/jni/exoplayer/opus_jni.cc +++ b/TMessagesProj/jni/exoplayer/opus_jni.cc @@ -28,10 +28,10 @@ __VA_ARGS__)) #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ - JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_opus_OpusDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) + JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \ - JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_opus_OpusLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) + JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__) // JNI references for SimpleOutputBuffer class. static jmethodID outputBufferInit; @@ -65,7 +65,7 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount, // Populate JNI References. const jclass outputBufferClass = env->FindClass( - "org/telegram/messenger/exoplayer2/decoder/SimpleOutputBuffer"); + "com/google/android/exoplayer2/decoder/SimpleOutputBuffer"); outputBufferInit = env->GetMethodID(outputBufferClass, "init", "(JI)Ljava/nio/ByteBuffer;"); diff --git a/TMessagesProj/jni/jni.c b/TMessagesProj/jni/jni.c index 860ffcd61..83c776350 100644 --- a/TMessagesProj/jni/jni.c +++ b/TMessagesProj/jni/jni.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,23 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en (*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0); } +JNIEXPORT jint Java_org_telegram_messenger_Utilities_pbkdf2(JNIEnv *env, jclass class, jbyteArray password, jbyteArray salt, jbyteArray dst, jint iterations) { + jbyte *passwordBuff = (*env)->GetByteArrayElements(env, password, NULL); + size_t passwordLength = (size_t) (*env)->GetArrayLength(env, password); + jbyte *saltBuff = (*env)->GetByteArrayElements(env, salt, NULL); + size_t saltLength = (size_t) (*env)->GetArrayLength(env, salt); + jbyte *dstBuff = (*env)->GetByteArrayElements(env, dst, NULL); + size_t dstLength = (size_t) (*env)->GetArrayLength(env, dst); + + int result = PKCS5_PBKDF2_HMAC((char *) passwordBuff, passwordLength, (uint8_t *) saltBuff, saltLength, (unsigned int) iterations, EVP_sha512(), dstLength, (uint8_t *) dstBuff); + + (*env)->ReleaseByteArrayElements(env, password, passwordBuff, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, salt, saltBuff, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, dst, dstBuff, 0); + + return result; +} + JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCtrDecryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, jint offset, jint length) { jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset; unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL); diff --git a/TMessagesProj/jni/libtgvoip b/TMessagesProj/jni/libtgvoip index 8faf6f670..23ae67306 160000 --- a/TMessagesProj/jni/libtgvoip +++ b/TMessagesProj/jni/libtgvoip @@ -1 +1 @@ -Subproject commit 8faf6f670037a8049ede4b85a004c40bdd359c6a +Subproject commit 23ae67306d7fa1c4d5a8a9c8653f63ab93100f88 diff --git a/TMessagesProj/proguard-rules.pro b/TMessagesProj/proguard-rules.pro index e90450113..09d2a0672 100644 --- a/TMessagesProj/proguard-rules.pro +++ b/TMessagesProj/proguard-rules.pro @@ -4,9 +4,12 @@ @com.google.android.gms.common.annotation.KeepName *; } -keep class org.telegram.** { *; } +-keep class com.google.android.exoplayer2.** { *; } -keep class com.coremedia.** { *; } +-keep class com.googlecode.mp4parser.** { *; } -dontwarn com.coremedia.** -dontwarn org.telegram.** +-dontwarn com.google.android.exoplayer2.** -dontwarn com.google.android.gms.** -dontwarn com.google.common.cache.** -dontwarn com.google.common.primitives.** diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index cc2840793..897c86e11 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + @@ -231,9 +232,9 @@ - + - + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/BaseRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/BaseRenderer.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/BaseRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index f4e821fa6..cb917b9b7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/BaseRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MediaClock; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/C.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/C.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/C.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/C.java index 57e815b2e..b09d57021 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/C.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/C.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.annotation.TargetApi; import android.content.Context; @@ -23,8 +23,8 @@ import android.media.MediaCodec; import android.media.MediaFormat; import android.support.annotation.IntDef; import android.view.Surface; -import org.telegram.messenger.exoplayer2.PlayerMessage.Target; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.PlayerMessage.Target; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.UUID; @@ -77,6 +77,12 @@ public final class C { */ public static final long NANOS_PER_SECOND = 1000000000L; + /** The number of bits per byte. */ + public static final int BITS_PER_BYTE = 8; + + /** The number of bytes per float. */ + public static final int BYTES_PER_FLOAT = 4; + /** * The name of the ASCII charset. */ @@ -136,6 +142,8 @@ public final class C { ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT, + ENCODING_PCM_MU_LAW, + ENCODING_PCM_A_LAW, ENCODING_AC3, ENCODING_E_AC3, ENCODING_DTS, @@ -144,12 +152,19 @@ public final class C { }) public @interface Encoding {} - /** - * Represents a PCM audio encoding, or an invalid or unset value. - */ + /** Represents a PCM audio encoding, or an invalid or unset value. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, - ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT}) + @IntDef({ + Format.NO_VALUE, + ENCODING_INVALID, + ENCODING_PCM_8BIT, + ENCODING_PCM_16BIT, + ENCODING_PCM_24BIT, + ENCODING_PCM_32BIT, + ENCODING_PCM_FLOAT, + ENCODING_PCM_MU_LAW, + ENCODING_PCM_A_LAW + }) public @interface PcmEncoding {} /** @see AudioFormat#ENCODING_INVALID */ public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID; @@ -163,6 +178,10 @@ public final class C { public static final int ENCODING_PCM_32BIT = 0x40000000; /** @see AudioFormat#ENCODING_PCM_FLOAT */ public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT; + /** Audio encoding for mu-law. */ + public static final int ENCODING_PCM_MU_LAW = 0x10000000; + /** Audio encoding for A-law. */ + public static final int ENCODING_PCM_A_LAW = 0x20000000; /** @see AudioFormat#ENCODING_AC3 */ public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; /** @see AudioFormat#ENCODING_E_AC3 */ @@ -226,7 +245,7 @@ public final class C { public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC; /** - * Content types for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}. + * Content types for {@link com.google.android.exoplayer2.audio.AudioAttributes}. */ @Retention(RetentionPolicy.SOURCE) @IntDef({CONTENT_TYPE_MOVIE, CONTENT_TYPE_MUSIC, CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_SPEECH, @@ -257,7 +276,7 @@ public final class C { android.media.AudioAttributes.CONTENT_TYPE_UNKNOWN; /** - * Flags for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}. + * Flags for {@link com.google.android.exoplayer2.audio.AudioAttributes}. *

* Note that {@code FLAG_HW_AV_SYNC} is not available because the player takes care of setting the * flag when tunneling is enabled via a track selector. @@ -272,7 +291,7 @@ public final class C { android.media.AudioAttributes.FLAG_AUDIBILITY_ENFORCED; /** - * Usage types for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}. + * Usage types for {@link com.google.android.exoplayer2.audio.AudioAttributes}. */ @Retention(RetentionPolicy.SOURCE) @IntDef({USAGE_ALARM, USAGE_ASSISTANCE_ACCESSIBILITY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, @@ -664,7 +683,7 @@ public final class C { /** * A type of a message that can be passed to an audio {@link Renderer} via {@link * ExoPlayer#createMessage(Target)}. The message payload should be an {@link - * org.telegram.messenger.exoplayer2.audio.AudioAttributes} instance that will configure the + * com.google.android.exoplayer2.audio.AudioAttributes} instance that will configure the * underlying audio track. If not set, the default audio attributes will be used. They are * suitable for general media playback. * @@ -797,6 +816,45 @@ public final class C { */ public static final int PRIORITY_DOWNLOAD = PRIORITY_PLAYBACK - 1000; + /** Network connection type. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + NETWORK_TYPE_UNKNOWN, + NETWORK_TYPE_OFFLINE, + NETWORK_TYPE_WIFI, + NETWORK_TYPE_2G, + NETWORK_TYPE_3G, + NETWORK_TYPE_4G, + NETWORK_TYPE_CELLULAR_UNKNOWN, + NETWORK_TYPE_ETHERNET, + NETWORK_TYPE_OTHER + }) + public @interface NetworkType {} + /** Unknown network type. */ + public static final int NETWORK_TYPE_UNKNOWN = 0; + /** No network connection. */ + public static final int NETWORK_TYPE_OFFLINE = 1; + /** Network type for a Wifi connection. */ + public static final int NETWORK_TYPE_WIFI = 2; + /** Network type for a 2G cellular connection. */ + public static final int NETWORK_TYPE_2G = 3; + /** Network type for a 3G cellular connection. */ + public static final int NETWORK_TYPE_3G = 4; + /** Network type for a 4G cellular connection. */ + public static final int NETWORK_TYPE_4G = 5; + /** + * Network type for cellular connections which cannot be mapped to one of {@link + * #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, or {@link #NETWORK_TYPE_4G}. + */ + public static final int NETWORK_TYPE_CELLULAR_UNKNOWN = 6; + /** Network type for an Ethernet connection. */ + public static final int NETWORK_TYPE_ETHERNET = 7; + /** + * Network type for other connections which are not Wifi or cellular (e.g. Ethernet, VPN, + * Bluetooth). + */ + public static final int NETWORK_TYPE_OTHER = 8; + /** * Converts a time in microseconds to the corresponding time in milliseconds, preserving * {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ControlDispatcher.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ControlDispatcher.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java index 1ebadbe48..f8749fc1a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ControlDispatcher.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.Player.RepeatMode; +import com.google.android.exoplayer2.Player.RepeatMode; /** * Dispatches operations to the {@link Player}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultControlDispatcher.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultControlDispatcher.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java index e83e5627b..df3ef36b8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultControlDispatcher.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.Player.RepeatMode; +import com.google.android.exoplayer2.Player.RepeatMode; /** * Default {@link ControlDispatcher} that dispatches all operations to the player without diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultLoadControl.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultLoadControl.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java index 5d83d8332..f8b7f5f5c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultLoadControl.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DefaultAllocator; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DefaultAllocator; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.util.Util; /** * The default {@link LoadControl} implementation. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultMediaClock.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultMediaClock.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java index 36946fc5b..ed57cec70 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultMediaClock.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.MediaClock; -import org.telegram.messenger.exoplayer2.util.StandaloneMediaClock; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.util.StandaloneMediaClock; /** * Default {@link MediaClock} which uses a renderer media clock and falls back to a diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultRenderersFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultRenderersFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index d3096ae3f..6cab53b78 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/DefaultRenderersFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.content.Context; import android.os.Handler; @@ -21,20 +21,20 @@ import android.os.Looper; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.audio.AudioCapabilities; -import org.telegram.messenger.exoplayer2.audio.AudioProcessor; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector; -import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; -import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer; -import org.telegram.messenger.exoplayer2.text.TextOutput; -import org.telegram.messenger.exoplayer2.text.TextRenderer; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer; -import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; +import com.google.android.exoplayer2.audio.AudioCapabilities; +import com.google.android.exoplayer2.audio.AudioProcessor; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; +import com.google.android.exoplayer2.metadata.MetadataOutput; +import com.google.android.exoplayer2.metadata.MetadataRenderer; +import com.google.android.exoplayer2.text.TextOutput; +import com.google.android.exoplayer2.text.TextRenderer; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; +import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Constructor; @@ -221,13 +221,13 @@ public class DefaultRenderersFactory implements RenderersFactory { try { // Full class names used for constructor args so the LINT rule triggers if any of them move. // LINT.IfChange - Class clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.vp9.LibvpxVideoRenderer"); + Class clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer"); Constructor constructor = clazz.getConstructor( boolean.class, long.class, android.os.Handler.class, - org.telegram.messenger.exoplayer2.video.VideoRendererEventListener.class, + com.google.android.exoplayer2.video.VideoRendererEventListener.class, int.class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = @@ -288,12 +288,12 @@ public class DefaultRenderersFactory implements RenderersFactory { try { // Full class names used for constructor args so the LINT rule triggers if any of them move. // LINT.IfChange - Class clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.opus.LibopusAudioRenderer"); + Class clazz = Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer"); Constructor constructor = clazz.getConstructor( android.os.Handler.class, - org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, - org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioRendererEventListener.class, + com.google.android.exoplayer2.audio.AudioProcessor[].class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); @@ -309,12 +309,12 @@ public class DefaultRenderersFactory implements RenderersFactory { try { // Full class names used for constructor args so the LINT rule triggers if any of them move. // LINT.IfChange - Class clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.flac.LibflacAudioRenderer"); + Class clazz = Class.forName("com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer"); Constructor constructor = clazz.getConstructor( android.os.Handler.class, - org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, - org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioRendererEventListener.class, + com.google.android.exoplayer2.audio.AudioProcessor[].class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); @@ -331,12 +331,12 @@ public class DefaultRenderersFactory implements RenderersFactory { // Full class names used for constructor args so the LINT rule triggers if any of them move. // LINT.IfChange Class clazz = - Class.forName("org.telegram.messenger.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer"); + Class.forName("com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer"); Constructor constructor = clazz.getConstructor( android.os.Handler.class, - org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, - org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioRendererEventListener.class, + com.google.android.exoplayer2.audio.AudioProcessor[].class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlaybackException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlaybackException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java index 4084984e4..ca7367f1b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlaybackException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayer.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 35305905b..0a0e2b014 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -13,24 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Looper; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer; -import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer; -import org.telegram.messenger.exoplayer2.source.ClippingMediaSource; -import org.telegram.messenger.exoplayer2.source.ConcatenatingMediaSource; -import org.telegram.messenger.exoplayer2.source.ExtractorMediaSource; -import org.telegram.messenger.exoplayer2.source.LoopingMediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MergingMediaSource; -import org.telegram.messenger.exoplayer2.source.SingleSampleMediaSource; -import org.telegram.messenger.exoplayer2.text.TextRenderer; -import org.telegram.messenger.exoplayer2.trackselection.DefaultTrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer; +import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; +import com.google.android.exoplayer2.metadata.MetadataRenderer; +import com.google.android.exoplayer2.source.ClippingMediaSource; +import com.google.android.exoplayer2.source.ConcatenatingMediaSource; +import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.LoopingMediaSource; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MergingMediaSource; +import com.google.android.exoplayer2.source.SingleSampleMediaSource; +import com.google.android.exoplayer2.text.TextRenderer; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; /** * An extensible media player that plays {@link MediaSource}s. Instances can be obtained from {@link @@ -89,12 +89,13 @@ import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer; * model"> * *

    - *
  • It is strongly recommended that ExoPlayer instances are created and accessed from a single - * application thread. The application's main thread is ideal. Accessing an instance from - * multiple threads is discouraged as it may cause synchronization problems. - *
  • Registered listeners are called on the thread that created the ExoPlayer instance, unless - * the thread that created the ExoPlayer instance does not have a {@link Looper}. In that - * case, registered listeners will be called on the application's main thread. + *
  • ExoPlayer instances must be accessed from the thread associated with {@link + * #getApplicationLooper()}. This Looper can be specified when creating the player, or this is + * the Looper of the thread the player is created on, or the Looper of the application's main + * thread if the player is created on a thread without Looper. + *
  • Registered listeners are called on the thread thread associated with {@link + * #getApplicationLooper()}. Note that this means registered listeners are called on the same + * thread which must be used to access the player. *
  • An internal playback thread is responsible for playback. Injected player components such as * Renderers, MediaSources, TrackSelectors and LoadControls are called by the player on this * thread. @@ -178,13 +179,15 @@ public interface ExoPlayer extends Player { @Deprecated @RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL; - /** - * Gets the {@link Looper} associated with the playback thread. - * - * @return The {@link Looper} associated with the playback thread. - */ + /** Returns the {@link Looper} associated with the playback thread. */ Looper getPlaybackLooper(); + /** + * Returns the {@link Looper} associated with the application thread that's used to access the + * player and on which player events are received. + */ + Looper getApplicationLooper(); + /** * Prepares the player to play the provided {@link MediaSource}. Equivalent to * {@code prepare(mediaSource, true, true)}. @@ -239,4 +242,7 @@ public interface ExoPlayer extends Player { * @param seekParameters The seek parameters, or {@code null} to use the defaults. */ void setSeekParameters(@Nullable SeekParameters seekParameters); + + /** Returns the currently active {@link SeekParameters} of the player. */ + SeekParameters getSeekParameters(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java similarity index 56% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java index 11eeb7ff9..bbbfa8fd0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java @@ -13,21 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.content.Context; +import android.os.Looper; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.util.Clock; +import com.google.android.exoplayer2.analytics.AnalyticsCollector; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.Util; /** * A factory for {@link ExoPlayer} instances. */ public final class ExoPlayerFactory { + private static @Nullable BandwidthMeter singletonBandwidthMeter; + private ExoPlayerFactory() {} /** @@ -155,8 +161,12 @@ public final class ExoPlayerFactory { */ public static SimpleExoPlayer newSimpleInstance(RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl) { - return new SimpleExoPlayer( - renderersFactory, trackSelector, loadControl, /* drmSessionManager= */ null); + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + /* drmSessionManager= */ null, + Util.getLooper()); } /** @@ -173,7 +183,34 @@ public final class ExoPlayerFactory { TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager) { - return new SimpleExoPlayer(renderersFactory, trackSelector, loadControl, drmSessionManager); + return newSimpleInstance( + renderersFactory, trackSelector, loadControl, drmSessionManager, Util.getLooper()); + } + + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance + * will not be used for DRM protected playbacks. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + bandwidthMeter, + new AnalyticsCollector.Factory(), + Util.getLooper()); } /** @@ -193,8 +230,100 @@ public final class ExoPlayerFactory { LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, AnalyticsCollector.Factory analyticsCollectorFactory) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + analyticsCollectorFactory, + Util.getLooper()); + } + + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance + * will not be used for DRM protected playbacks. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + Looper looper) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + new AnalyticsCollector.Factory(), + looper); + } + + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance + * will not be used for DRM protected playbacks. + * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that + * will collect and forward all player events. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + AnalyticsCollector.Factory analyticsCollectorFactory, + Looper looper) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + getDefaultBandwidthMeter(), + analyticsCollectorFactory, + looper); + } + + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance + * will not be used for DRM protected playbacks. + * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that + * will collect and forward all player events. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, + AnalyticsCollector.Factory analyticsCollectorFactory, + Looper looper) { return new SimpleExoPlayer( - renderersFactory, trackSelector, loadControl, drmSessionManager, analyticsCollectorFactory); + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + bandwidthMeter, + analyticsCollectorFactory, + looper); } /** @@ -216,7 +345,47 @@ public final class ExoPlayerFactory { */ public static ExoPlayer newInstance(Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) { - return new ExoPlayerImpl(renderers, trackSelector, loadControl, Clock.DEFAULT); + return newInstance(renderers, trackSelector, loadControl, Util.getLooper()); } + /** + * Creates an {@link ExoPlayer} instance. + * + * @param renderers The {@link Renderer}s that will be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. + */ + public static ExoPlayer newInstance( + Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Looper looper) { + return newInstance(renderers, trackSelector, loadControl, getDefaultBandwidthMeter(), looper); + } + + /** + * Creates an {@link ExoPlayer} instance. + * + * @param renderers The {@link Renderer}s that will be used by the instance. + * @param trackSelector The {@link TrackSelector} that will be used by the instance. + * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. + */ + public static ExoPlayer newInstance( + Renderer[] renderers, + TrackSelector trackSelector, + LoadControl loadControl, + BandwidthMeter bandwidthMeter, + Looper looper) { + return new ExoPlayerImpl( + renderers, trackSelector, loadControl, bandwidthMeter, Clock.DEFAULT, looper); + } + + private static synchronized BandwidthMeter getDefaultBandwidthMeter() { + if (singletonBandwidthMeter == null) { + singletonBandwidthMeter = new DefaultBandwidthMeter.Builder().build(); + } + return singletonBandwidthMeter; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImpl.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java similarity index 68% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImpl.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 4e37e32b5..0435d221f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImpl.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.annotation.SuppressLint; import android.os.Handler; @@ -22,19 +22,22 @@ import android.os.Message; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; -import org.telegram.messenger.exoplayer2.PlayerMessage.Target; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.PlayerMessage.Target; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectorResult; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.Util; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; /** @@ -53,6 +56,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private final CopyOnWriteArraySet listeners; private final Timeline.Window window; private final Timeline.Period period; + private final ArrayDeque pendingPlaybackInfoUpdates; private boolean playWhenReady; private @RepeatMode int repeatMode; @@ -61,6 +65,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private boolean hasPendingPrepare; private boolean hasPendingSeek; private PlaybackParameters playbackParameters; + private SeekParameters seekParameters; private @Nullable ExoPlaybackException playbackError; // Playback information when there is no pending seek/set source operation. @@ -77,11 +82,19 @@ import java.util.concurrent.CopyOnWriteArraySet; * @param renderers The {@link Renderer}s that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. * @param clock The {@link Clock} that will be used by the instance. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. */ @SuppressLint("HandlerLeak") public ExoPlayerImpl( - Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Clock clock) { + Renderer[] renderers, + TrackSelector trackSelector, + LoadControl loadControl, + BandwidthMeter bandwidthMeter, + Clock clock, + Looper looper) { Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " [" + ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "]"); Assertions.checkState(renderers.length > 0); @@ -99,25 +112,23 @@ import java.util.concurrent.CopyOnWriteArraySet; window = new Timeline.Window(); period = new Timeline.Period(); playbackParameters = PlaybackParameters.DEFAULT; - Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); - eventHandler = new Handler(eventLooper) { - @Override - public void handleMessage(Message msg) { - ExoPlayerImpl.this.handleEvent(msg); - } - }; - playbackInfo = - new PlaybackInfo( - Timeline.EMPTY, - /* startPositionUs= */ 0, - TrackGroupArray.EMPTY, - emptyTrackSelectorResult); + seekParameters = SeekParameters.DEFAULT; + eventHandler = + new Handler(looper) { + @Override + public void handleMessage(Message msg) { + ExoPlayerImpl.this.handleEvent(msg); + } + }; + playbackInfo = PlaybackInfo.createDummy(/* startPositionUs= */ 0, emptyTrackSelectorResult); + pendingPlaybackInfoUpdates = new ArrayDeque<>(); internalPlayer = new ExoPlayerImplInternal( renderers, trackSelector, emptyTrackSelectorResult, loadControl, + bandwidthMeter, playWhenReady, repeatMode, shuffleModeEnabled, @@ -127,6 +138,11 @@ import java.util.concurrent.CopyOnWriteArraySet; internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper()); } + @Override + public AudioComponent getAudioComponent() { + return null; + } + @Override public VideoComponent getVideoComponent() { return null; @@ -142,6 +158,11 @@ import java.util.concurrent.CopyOnWriteArraySet; return internalPlayer.getPlaybackLooper(); } + @Override + public Looper getApplicationLooper() { + return eventHandler.getLooper(); + } + @Override public void addListener(Player.EventListener listener) { listeners.add(listener); @@ -185,7 +206,8 @@ import java.util.concurrent.CopyOnWriteArraySet; /* positionDiscontinuity= */ false, /* ignored */ DISCONTINUITY_REASON_INTERNAL, TIMELINE_CHANGE_REASON_RESET, - /* seekProcessed= */ false); + /* seekProcessed= */ false, + /* playWhenReadyChanged= */ false); } @Override @@ -193,10 +215,13 @@ import java.util.concurrent.CopyOnWriteArraySet; if (this.playWhenReady != playWhenReady) { this.playWhenReady = playWhenReady; internalPlayer.setPlayWhenReady(playWhenReady); - PlaybackInfo playbackInfo = this.playbackInfo; - for (Player.EventListener listener : listeners) { - listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); - } + updatePlaybackInfo( + playbackInfo, + /* positionDiscontinuity= */ false, + /* ignored */ DISCONTINUITY_REASON_INTERNAL, + /* ignored */ TIMELINE_CHANGE_REASON_RESET, + /* seekProcessed= */ false, + /* playWhenReadyChanged= */ true); } } @@ -286,10 +311,10 @@ import java.util.concurrent.CopyOnWriteArraySet; } else { long windowPositionUs = positionMs == C.TIME_UNSET ? timeline.getWindow(windowIndex, window).getDefaultPositionUs() : C.msToUs(positionMs); - Pair periodIndexAndPositon = + Pair periodIndexAndPosition = timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs); maskingWindowPositionMs = C.usToMs(windowPositionUs); - maskingPeriodIndex = periodIndexAndPositon.first; + maskingPeriodIndex = periodIndexAndPosition.first; } internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs)); for (Player.EventListener listener : listeners) { @@ -315,7 +340,15 @@ import java.util.concurrent.CopyOnWriteArraySet; if (seekParameters == null) { seekParameters = SeekParameters.DEFAULT; } - internalPlayer.setSeekParameters(seekParameters); + if (!this.seekParameters.equals(seekParameters)) { + this.seekParameters = seekParameters; + internalPlayer.setSeekParameters(seekParameters); + } + } + + @Override + public SeekParameters getSeekParameters() { + return seekParameters; } @Override @@ -352,7 +385,8 @@ import java.util.concurrent.CopyOnWriteArraySet; /* positionDiscontinuity= */ false, /* ignored */ DISCONTINUITY_REASON_INTERNAL, TIMELINE_CHANGE_REASON_RESET, - /* seekProcessed= */ false); + /* seekProcessed= */ false, + /* playWhenReadyChanged= */ false); } @Override @@ -461,29 +495,37 @@ import java.util.concurrent.CopyOnWriteArraySet; public long getCurrentPosition() { if (shouldMaskPosition()) { return maskingWindowPositionMs; + } else if (playbackInfo.periodId.isAd()) { + return C.usToMs(playbackInfo.positionUs); } else { - return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs); + return periodPositionUsToWindowPositionMs(playbackInfo.periodId, playbackInfo.positionUs); } } @Override public long getBufferedPosition() { - // TODO - Implement this properly. - if (shouldMaskPosition()) { - return maskingWindowPositionMs; - } else { - return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs); + if (isPlayingAd()) { + return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId) + ? C.usToMs(playbackInfo.bufferedPositionUs) + : getDuration(); } + return getContentBufferedPosition(); } @Override public int getBufferedPercentage() { long position = getBufferedPosition(); long duration = getDuration(); - return position == C.TIME_UNSET || duration == C.TIME_UNSET ? 0 + return position == C.TIME_UNSET || duration == C.TIME_UNSET + ? 0 : (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100)); } + @Override + public long getTotalBufferedDuration() { + return Math.max(0, C.usToMs(playbackInfo.totalBufferedDurationUs)); + } + @Override public boolean isCurrentWindowDynamic() { Timeline timeline = playbackInfo.timeline; @@ -521,6 +563,29 @@ import java.util.concurrent.CopyOnWriteArraySet; } } + @Override + public long getContentBufferedPosition() { + if (shouldMaskPosition()) { + return maskingWindowPositionMs; + } + if (playbackInfo.loadingMediaPeriodId.windowSequenceNumber + != playbackInfo.periodId.windowSequenceNumber) { + return playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + } + long contentBufferedPositionUs = playbackInfo.bufferedPositionUs; + if (playbackInfo.loadingMediaPeriodId.isAd()) { + Timeline.Period loadingPeriod = + playbackInfo.timeline.getPeriod(playbackInfo.loadingMediaPeriodId.periodIndex, period); + contentBufferedPositionUs = + loadingPeriod.getAdGroupTimeUs(playbackInfo.loadingMediaPeriodId.adGroupIndex); + if (contentBufferedPositionUs == C.TIME_END_OF_SOURCE) { + contentBufferedPositionUs = loadingPeriod.durationUs; + } + } + return periodPositionUsToWindowPositionMs( + playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs); + } + @Override public int getRendererCount() { return renderers.length; @@ -615,7 +680,8 @@ import java.util.concurrent.CopyOnWriteArraySet; positionDiscontinuity, positionDiscontinuityReason, timelineChangeReason, - seekProcessed); + seekProcessed, + /* playWhenReadyChanged= */ false); } } @@ -639,68 +705,133 @@ import java.util.concurrent.CopyOnWriteArraySet; playbackState, /* isLoading= */ false, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, - resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); + resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, + playbackInfo.periodId, + playbackInfo.startPositionUs, + /* totalBufferedDurationUs= */ 0, + playbackInfo.startPositionUs); } private void updatePlaybackInfo( - PlaybackInfo newPlaybackInfo, + PlaybackInfo playbackInfo, boolean positionDiscontinuity, @Player.DiscontinuityReason int positionDiscontinuityReason, @Player.TimelineChangeReason int timelineChangeReason, - boolean seekProcessed) { - boolean timelineOrManifestChanged = - playbackInfo.timeline != newPlaybackInfo.timeline - || playbackInfo.manifest != newPlaybackInfo.manifest; - boolean playbackStateChanged = playbackInfo.playbackState != newPlaybackInfo.playbackState; - boolean isLoadingChanged = playbackInfo.isLoading != newPlaybackInfo.isLoading; - boolean trackSelectorResultChanged = - playbackInfo.trackSelectorResult != newPlaybackInfo.trackSelectorResult; - playbackInfo = newPlaybackInfo; - if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) { - for (Player.EventListener listener : listeners) { - listener.onTimelineChanged( - playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason); - } + boolean seekProcessed, + boolean playWhenReadyChanged) { + boolean isRunningRecursiveListenerNotification = !pendingPlaybackInfoUpdates.isEmpty(); + pendingPlaybackInfoUpdates.addLast( + new PlaybackInfoUpdate( + playbackInfo, + /* previousPlaybackInfo= */ this.playbackInfo, + listeners, + trackSelector, + positionDiscontinuity, + positionDiscontinuityReason, + timelineChangeReason, + seekProcessed, + playWhenReady, + playWhenReadyChanged)); + // Assign playback info immediately such that all getters return the right values. + this.playbackInfo = playbackInfo; + if (isRunningRecursiveListenerNotification) { + return; } - if (positionDiscontinuity) { - for (Player.EventListener listener : listeners) { - listener.onPositionDiscontinuity(positionDiscontinuityReason); - } - } - if (trackSelectorResultChanged) { - trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info); - for (Player.EventListener listener : listeners) { - listener.onTracksChanged( - playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections); - } - } - if (isLoadingChanged) { - for (Player.EventListener listener : listeners) { - listener.onLoadingChanged(playbackInfo.isLoading); - } - } - if (playbackStateChanged) { - for (Player.EventListener listener : listeners) { - listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); - } - } - if (seekProcessed) { - for (Player.EventListener listener : listeners) { - listener.onSeekProcessed(); - } + while (!pendingPlaybackInfoUpdates.isEmpty()) { + pendingPlaybackInfoUpdates.peekFirst().notifyListeners(); + pendingPlaybackInfoUpdates.removeFirst(); } } - private long playbackInfoPositionUsToWindowPositionMs(long positionUs) { + private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) { long positionMs = C.usToMs(positionUs); - if (!playbackInfo.periodId.isAd()) { - playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period); - positionMs += period.getPositionInWindowMs(); - } + playbackInfo.timeline.getPeriod(periodId.periodIndex, period); + positionMs += period.getPositionInWindowMs(); return positionMs; } private boolean shouldMaskPosition() { return playbackInfo.timeline.isEmpty() || pendingOperationAcks > 0; } + + private static final class PlaybackInfoUpdate { + + private final PlaybackInfo playbackInfo; + private final Set listeners; + private final TrackSelector trackSelector; + private final boolean positionDiscontinuity; + private final @Player.DiscontinuityReason int positionDiscontinuityReason; + private final @Player.TimelineChangeReason int timelineChangeReason; + private final boolean seekProcessed; + private final boolean playWhenReady; + private final boolean playbackStateOrPlayWhenReadyChanged; + private final boolean timelineOrManifestChanged; + private final boolean isLoadingChanged; + private final boolean trackSelectorResultChanged; + + public PlaybackInfoUpdate( + PlaybackInfo playbackInfo, + PlaybackInfo previousPlaybackInfo, + Set listeners, + TrackSelector trackSelector, + boolean positionDiscontinuity, + @Player.DiscontinuityReason int positionDiscontinuityReason, + @Player.TimelineChangeReason int timelineChangeReason, + boolean seekProcessed, + boolean playWhenReady, + boolean playWhenReadyChanged) { + this.playbackInfo = playbackInfo; + this.listeners = listeners; + this.trackSelector = trackSelector; + this.positionDiscontinuity = positionDiscontinuity; + this.positionDiscontinuityReason = positionDiscontinuityReason; + this.timelineChangeReason = timelineChangeReason; + this.seekProcessed = seekProcessed; + this.playWhenReady = playWhenReady; + playbackStateOrPlayWhenReadyChanged = + playWhenReadyChanged || previousPlaybackInfo.playbackState != playbackInfo.playbackState; + timelineOrManifestChanged = + previousPlaybackInfo.timeline != playbackInfo.timeline + || previousPlaybackInfo.manifest != playbackInfo.manifest; + isLoadingChanged = previousPlaybackInfo.isLoading != playbackInfo.isLoading; + trackSelectorResultChanged = + previousPlaybackInfo.trackSelectorResult != playbackInfo.trackSelectorResult; + } + + public void notifyListeners() { + if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) { + for (Player.EventListener listener : listeners) { + listener.onTimelineChanged( + playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason); + } + } + if (positionDiscontinuity) { + for (Player.EventListener listener : listeners) { + listener.onPositionDiscontinuity(positionDiscontinuityReason); + } + } + if (trackSelectorResultChanged) { + trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info); + for (Player.EventListener listener : listeners) { + listener.onTracksChanged( + playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections); + } + } + if (isLoadingChanged) { + for (Player.EventListener listener : listeners) { + listener.onLoadingChanged(playbackInfo.isLoading); + } + } + if (playbackStateOrPlayWhenReadyChanged) { + for (Player.EventListener listener : listeners) { + listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); + } + } + if (seekProcessed) { + for (Player.EventListener listener : listeners) { + listener.onSeekProcessed(); + } + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImplInternal.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImplInternal.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index d9b72a361..a4b123884 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerImplInternal.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Handler; import android.os.HandlerThread; @@ -25,21 +25,22 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; -import org.telegram.messenger.exoplayer2.DefaultMediaClock.PlaybackParameterListener; -import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.HandlerWrapper; -import org.telegram.messenger.exoplayer2.util.TraceUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParameterListener; +import com.google.android.exoplayer2.Player.DiscontinuityReason; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectorResult; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.HandlerWrapper; +import com.google.android.exoplayer2.util.TraceUtil; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -77,6 +78,7 @@ import java.util.Collections; private static final int MSG_SET_SHUFFLE_ENABLED = 13; private static final int MSG_SEND_MESSAGE = 14; private static final int MSG_SEND_MESSAGE_TO_TARGET_THREAD = 15; + private static final int MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL = 16; private static final int PREPARING_SOURCE_INTERVAL_MS = 10; private static final int RENDERING_INTERVAL_MS = 10; @@ -87,6 +89,7 @@ import java.util.Collections; private final TrackSelector trackSelector; private final TrackSelectorResult emptyTrackSelectorResult; private final LoadControl loadControl; + private final BandwidthMeter bandwidthMeter; private final HandlerWrapper handler; private final HandlerThread internalPlaybackThread; private final Handler eventHandler; @@ -123,6 +126,7 @@ import java.util.Collections; TrackSelector trackSelector, TrackSelectorResult emptyTrackSelectorResult, LoadControl loadControl, + BandwidthMeter bandwidthMeter, boolean playWhenReady, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, @@ -133,6 +137,7 @@ import java.util.Collections; this.trackSelector = trackSelector; this.emptyTrackSelectorResult = emptyTrackSelectorResult; this.loadControl = loadControl; + this.bandwidthMeter = bandwidthMeter; this.playWhenReady = playWhenReady; this.repeatMode = repeatMode; this.shuffleModeEnabled = shuffleModeEnabled; @@ -146,11 +151,7 @@ import java.util.Collections; seekParameters = SeekParameters.DEFAULT; playbackInfo = - new PlaybackInfo( - Timeline.EMPTY, - /* startPositionUs= */ C.TIME_UNSET, - TrackGroupArray.EMPTY, - emptyTrackSelectorResult); + PlaybackInfo.createDummy(/* startPositionUs= */ C.TIME_UNSET, emptyTrackSelectorResult); playbackInfoUpdate = new PlaybackInfoUpdate(); rendererCapabilities = new RendererCapabilities[renderers.length]; for (int i = 0; i < renderers.length; i++) { @@ -162,7 +163,7 @@ import java.util.Collections; enabledRenderers = new Renderer[0]; window = new Timeline.Window(); period = new Timeline.Period(); - trackSelector.init(this); + trackSelector.init(/* listener= */ this, bandwidthMeter); // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // not normally change to this priority" is incorrect. @@ -271,8 +272,9 @@ import java.util.Collections; @Override public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { - eventHandler.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED, playbackParameters).sendToTarget(); - updateTrackSelectionPlaybackSpeed(playbackParameters.speed); + handler + .obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, playbackParameters) + .sendToTarget(); } // Handler.Callback implementation. @@ -324,6 +326,9 @@ import java.util.Collections; case MSG_TRACK_SELECTION_INVALIDATED: reselectTracksInternal(); break; + case MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL: + handlePlaybackParameters((PlaybackParameters) msg.obj); + break; case MSG_SEND_MESSAGE: sendMessageInternal((PlayerMessage) msg.obj); break; @@ -393,7 +398,11 @@ import java.util.Collections; loadControl.onPrepared(); this.mediaSource = mediaSource; setState(Player.STATE_BUFFERING); - mediaSource.prepareSource(player, /* isTopLevelSource= */ true, /* listener= */ this); + mediaSource.prepareSource( + player, + /* isTopLevelSource= */ true, + /* listener= */ this, + bandwidthMeter.getTransferListener()); handler.sendEmptyMessage(MSG_DO_SOME_WORK); } @@ -419,6 +428,7 @@ import java.util.Collections; if (!queue.updateRepeatMode(repeatMode)) { seekToCurrentPosition(/* sendDiscontinuity= */ true); } + updateLoadingMediaPeriodId(); } private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled) @@ -427,6 +437,7 @@ import java.util.Collections; if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) { seekToCurrentPosition(/* sendDiscontinuity= */ true); } + updateLoadingMediaPeriodId(); } private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException { @@ -483,11 +494,12 @@ import java.util.Collections; playbackInfo.positionUs = periodPositionUs; } - // Update the buffered position. + // Update the buffered position and total buffered duration. + MediaPeriodHolder loadingPeriod = queue.getLoadingPeriod(); playbackInfo.bufferedPositionUs = - enabledRenderers.length == 0 - ? playingPeriodHolder.info.durationUs - : playingPeriodHolder.getBufferedPositionUs(/* convertEosToDuration= */ true); + loadingPeriod.getBufferedPositionUs(/* convertEosToDuration= */ true); + playbackInfo.totalBufferedDurationUs = + playbackInfo.bufferedPositionUs - loadingPeriod.toPeriodTime(rendererPositionUs); } private void doSomeWork() throws ExoPlaybackException, IOException { @@ -587,7 +599,7 @@ import java.util.Collections; if (resolvedSeekPosition == null) { // The seek position was valid for the timeline that it was performed into, but the // timeline has changed or is not ready and a suitable seek position could not be resolved. - periodId = new MediaPeriodId(getFirstPeriodIndex()); + periodId = getFirstMediaPeriodId(); periodPositionUs = C.TIME_UNSET; contentPositionUs = C.TIME_UNSET; seekPositionAdjusted = true; @@ -660,7 +672,7 @@ import java.util.Collections; MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder newPlayingPeriodHolder = oldPlayingPeriodHolder; while (newPlayingPeriodHolder != null) { - if (shouldKeepPeriodHolder(periodId, periodPositionUs, newPlayingPeriodHolder)) { + if (periodId.equals(newPlayingPeriodHolder.info.id) && newPlayingPeriodHolder.prepared) { queue.removeAfter(newPlayingPeriodHolder); break; } @@ -691,23 +703,11 @@ import java.util.Collections; resetRendererPosition(periodPositionUs); } + updateLoadingMediaPeriodId(); handler.sendEmptyMessage(MSG_DO_SOME_WORK); return periodPositionUs; } - private boolean shouldKeepPeriodHolder( - MediaPeriodId seekPeriodId, long positionUs, MediaPeriodHolder holder) { - if (seekPeriodId.equals(holder.info.id) && holder.prepared) { - playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period); - int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs); - if (nextAdGroupIndex == C.INDEX_UNSET - || period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) { - return true; - } - } - return false; - } - private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException { rendererPositionUs = !queue.hasPlayingPeriod() @@ -749,12 +749,15 @@ import java.util.Collections; } } - private int getFirstPeriodIndex() { + private MediaPeriodId getFirstMediaPeriodId() { Timeline timeline = playbackInfo.timeline; - return timeline.isEmpty() - ? 0 - : timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window) + if (timeline.isEmpty()) { + return PlaybackInfo.DUMMY_MEDIA_PERIOD_ID; + } + int firstPeriodIndex = + timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window) .firstPeriodIndex; + return new MediaPeriodId(firstPeriodIndex); } private void resetInternal( @@ -785,18 +788,25 @@ import java.util.Collections; pendingMessages.clear(); nextPendingMessageIndex = 0; } + // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored. + MediaPeriodId mediaPeriodId = resetPosition ? getFirstMediaPeriodId() : playbackInfo.periodId; + long startPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.positionUs; + long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs; playbackInfo = new PlaybackInfo( resetState ? Timeline.EMPTY : playbackInfo.timeline, resetState ? null : playbackInfo.manifest, - resetPosition ? new MediaPeriodId(getFirstPeriodIndex()) : playbackInfo.periodId, - // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored. - resetPosition ? C.TIME_UNSET : playbackInfo.positionUs, - resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs, + mediaPeriodId, + startPositionUs, + contentPositionUs, playbackInfo.playbackState, /* isLoading= */ false, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, - resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); + resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, + mediaPeriodId, + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); if (releaseMediaSource) { if (mediaSource != null) { mediaSource.releaseSource(/* listener= */ this); @@ -892,7 +902,7 @@ import java.util.Collections; pendingMessageInfo.setResolvedPosition( periodPosition.first, periodPosition.second, - playbackInfo.timeline.getPeriod(periodPosition.first, period, true).uid); + playbackInfo.timeline.getUidOfPeriod(periodPosition.first)); } else { // Position has been resolved for a previous timeline. Try to find the updated period index. int index = playbackInfo.timeline.getIndexOfPeriod(pendingMessageInfo.resolvedPeriodUid); @@ -1051,6 +1061,7 @@ import java.util.Collections; updateLoadControlTrackSelection(periodHolder.trackGroups, periodHolder.trackSelectorResult); } } + updateLoadingMediaPeriodId(); if (playbackInfo.playbackState != Player.STATE_ENDED) { maybeContinueLoading(); updatePlaybackPositions(); @@ -1142,8 +1153,15 @@ import java.util.Collections; playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount); pendingPrepareCount = 0; if (pendingInitialSeekPosition != null) { - Pair periodPosition = - resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); + Pair periodPosition; + try { + periodPosition = + resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); + } catch (IllegalSeekPositionException e) { + playbackInfo = + playbackInfo.fromNewPosition(getFirstMediaPeriodId(), C.TIME_UNSET, C.TIME_UNSET); + throw e; + } pendingInitialSeekPosition = null; if (periodPosition == null) { // The seek position was valid for the timeline that it was performed into, but the @@ -1176,22 +1194,28 @@ import java.util.Collections; return; } - int playingPeriodIndex = playbackInfo.periodId.periodIndex; - long contentPositionUs = playbackInfo.contentPositionUs; if (oldTimeline.isEmpty()) { // If the old timeline is empty, the period queue is also empty. if (!timeline.isEmpty()) { - MediaPeriodId periodId = - queue.resolveMediaPeriodIdForAds(playingPeriodIndex, contentPositionUs); + Pair defaultPosition = + getPeriodPosition( + timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); + int periodIndex = defaultPosition.first; + long startPositionUs = defaultPosition.second; + MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, startPositionUs); playbackInfo = playbackInfo.fromNewPosition( - periodId, periodId.isAd() ? 0 : contentPositionUs, contentPositionUs); + periodId, + /* startPositionUs= */ periodId.isAd() ? 0 : startPositionUs, + /* contentPositionUs= */ startPositionUs); } return; } MediaPeriodHolder periodHolder = queue.getFrontPeriod(); - Object playingPeriodUid = periodHolder == null - ? oldTimeline.getPeriod(playingPeriodIndex, period, true).uid : periodHolder.uid; + int playingPeriodIndex = playbackInfo.periodId.periodIndex; + long contentPositionUs = playbackInfo.contentPositionUs; + Object playingPeriodUid = + periodHolder == null ? oldTimeline.getUidOfPeriod(playingPeriodIndex) : periodHolder.uid; int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid); if (periodIndex == C.INDEX_UNSET) { // We didn't find the current period in the new timeline. Attempt to resolve a subsequent @@ -1208,11 +1232,10 @@ import java.util.Collections; newPeriodIndex = defaultPosition.first; contentPositionUs = defaultPosition.second; MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodIndex, contentPositionUs); - timeline.getPeriod(newPeriodIndex, period, true); if (periodHolder != null) { // Clear the index of each holder that doesn't contain the default position. If a holder // contains the default position then update its index so it can be re-used when seeking. - Object newPeriodUid = period.uid; + Object newPeriodUid = timeline.getUidOfPeriod(newPeriodIndex); periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); while (periodHolder.next != null) { periodHolder = periodHolder.next; @@ -1249,6 +1272,7 @@ import java.util.Collections; if (!queue.updateQueuedPeriods(playingPeriodId, rendererPositionUs)) { seekToCurrentPosition(/* sendDiscontinuity= */ false); } + updateLoadingMediaPeriodId(); } private void handleSourceInfoRefreshEndedPlayback() { @@ -1279,8 +1303,7 @@ import java.util.Collections; // We've reached the end of the old timeline. break; } - newPeriodIndex = newTimeline.getIndexOfPeriod( - oldTimeline.getPeriod(oldPeriodIndex, period, true).uid); + newPeriodIndex = newTimeline.getIndexOfPeriod(oldTimeline.getUidOfPeriod(oldPeriodIndex)); } return newPeriodIndex; } @@ -1324,8 +1347,7 @@ import java.util.Collections; return periodPosition; } // Attempt to find the mapped period in the internal timeline. - int periodIndex = timeline.getIndexOfPeriod( - seekTimeline.getPeriod(periodPosition.first, period, true).uid); + int periodIndex = timeline.getIndexOfPeriod(seekTimeline.getUidOfPeriod(periodPosition.first)); if (periodIndex != C.INDEX_UNSET) { // We successfully located the period in the internal timeline. return Pair.create(periodIndex, periodPosition.second); @@ -1483,7 +1505,7 @@ import java.util.Collections; if (info == null) { mediaSource.maybeThrowSourceInfoRefreshError(); } else { - Object uid = playbackInfo.timeline.getPeriod(info.id.periodIndex, period, true).uid; + Object uid = playbackInfo.timeline.getUidOfPeriod(info.id.periodIndex); MediaPeriod mediaPeriod = queue.enqueueNextMediaPeriod( rendererCapabilities, @@ -1494,6 +1516,7 @@ import java.util.Collections; info); mediaPeriod.prepare(this, info.startPositionUs); setIsLoading(true); + updateLoadingMediaPeriodId(); } } } @@ -1525,6 +1548,17 @@ import java.util.Collections; maybeContinueLoading(); } + private void handlePlaybackParameters(PlaybackParameters playbackParameters) + throws ExoPlaybackException { + eventHandler.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED, playbackParameters).sendToTarget(); + updateTrackSelectionPlaybackSpeed(playbackParameters.speed); + for (Renderer renderer : renderers) { + if (renderer != null) { + renderer.setOperatingRate(playbackParameters.speed); + } + } + } + private void maybeContinueLoading() { MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod(); long nextLoadPositionUs = loadingPeriodHolder.getNextLoadPositionUs(); @@ -1543,6 +1577,7 @@ import java.util.Collections; } } + @SuppressWarnings("ParameterNotNullable") private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder) throws ExoPlaybackException { MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod(); @@ -1619,6 +1654,13 @@ import java.util.Collections; && renderer.hasReadStreamToEnd(); } + private void updateLoadingMediaPeriodId() { + MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod(); + MediaPeriodId loadingMediaPeriodId = + loadingMediaPeriodHolder == null ? playbackInfo.periodId : loadingMediaPeriodHolder.info.id; + playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(loadingMediaPeriodId); + } + @NonNull private static Format[] getFormats(TrackSelection newSelection) { // Build an array of formats contained by the selection. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerLibraryInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerLibraryInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 864093054..fef4b0f30 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ExoPlayerLibraryInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import java.util.HashSet; @@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo { /** The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.8.1"; + public static final String VERSION = "2.8.3"; /** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.8.1"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.8.3"; /** * The version of the library expressed as an integer, for example 1002003. @@ -43,16 +43,19 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2008001; + public static final int VERSION_INT = 2008003; /** - * Whether the library was compiled with {@link org.telegram.messenger.exoplayer2.util.Assertions} + * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} * checks enabled. */ public static final boolean ASSERTIONS_ENABLED = true; + /** Whether an exception should be thrown in case of an OpenGl error. */ + public static final boolean GL_ASSERTIONS_ENABLED = false; + /** - * Whether the library was compiled with {@link org.telegram.messenger.exoplayer2.util.TraceUtil} + * Whether the library was compiled with {@link com.google.android.exoplayer2.util.TraceUtil} * trace enabled. */ public static final boolean TRACE_ENABLED = true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Format.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Format.java similarity index 51% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Format.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/Format.java index 8ad7c810e..459c56ee0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Format.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Format.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.video.ColorInfo; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.ColorInfo; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -46,6 +46,9 @@ public final class Format implements Parcelable { /** An identifier for the format, or null if unknown or not applicable. */ public final @Nullable String id; + /** The human readable label, or null if unknown or not applicable. */ + public final @Nullable String label; + /** * The average bandwidth in bits per second, or {@link #NO_VALUE} if unknown or not applicable. */ @@ -80,6 +83,13 @@ public final class Format implements Parcelable { /** DRM initialization data if the stream is protected, or null otherwise. */ public final @Nullable DrmInitData drmInitData; + /** + * For samples that contain subsamples, this is an offset that should be added to subsample + * timestamps. A value of {@link #OFFSET_SAMPLE_RELATIVE} indicates that subsample timestamps are + * relative to the timestamps of their parent samples. + */ + public final long subsampleOffsetUs; + // Video specific. /** @@ -125,12 +135,12 @@ public final class Format implements Parcelable { public final int sampleRate; /** * The encoding for PCM audio streams. If {@link #sampleMimeType} is {@link MimeTypes#AUDIO_RAW} - * then one of {@link C#ENCODING_PCM_8BIT}, {@link C#ENCODING_PCM_16BIT}, - * {@link C#ENCODING_PCM_24BIT} and {@link C#ENCODING_PCM_32BIT}. Set to {@link #NO_VALUE} for - * other media types. + * then one of {@link C#ENCODING_PCM_8BIT}, {@link C#ENCODING_PCM_16BIT}, {@link + * C#ENCODING_PCM_24BIT}, {@link C#ENCODING_PCM_32BIT}, {@link C#ENCODING_PCM_FLOAT}, {@link + * C#ENCODING_PCM_MU_LAW} or {@link C#ENCODING_PCM_A_LAW}. Set to {@link #NO_VALUE} for other + * media types. */ - @C.PcmEncoding - public final int pcmEncoding; + public final @C.PcmEncoding int pcmEncoding; /** * The number of frames to trim from the start of the decoded audio stream, or 0 if not * applicable. @@ -141,15 +151,6 @@ public final class Format implements Parcelable { */ public final int encoderPadding; - // Text specific. - - /** - * For samples that contain subsamples, this is an offset that should be added to subsample - * timestamps. A value of {@link #OFFSET_SAMPLE_RELATIVE} indicates that subsample timestamps are - * relative to the timestamps of their parent samples. - */ - public final long subsampleOffsetUs; - // Audio and text specific. /** @@ -171,6 +172,7 @@ public final class Format implements Parcelable { // Video. + @Deprecated public static Format createVideoContainerFormat( @Nullable String id, @Nullable String containerMimeType, @@ -180,12 +182,62 @@ public final class Format implements Parcelable { int width, int height, float frameRate, - List initializationData, + @Nullable List initializationData, @C.SelectionFlags int selectionFlags) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width, - height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, selectionFlags, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, - initializationData, null, null); + return createVideoContainerFormat( + id, + /* label= */ null, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + width, + height, + frameRate, + initializationData, + selectionFlags); + } + + public static Format createVideoContainerFormat( + @Nullable String id, + @Nullable String label, + @Nullable String containerMimeType, + String sampleMimeType, + String codecs, + int bitrate, + int width, + int height, + float frameRate, + @Nullable List initializationData, + @C.SelectionFlags int selectionFlags) { + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + width, + height, + frameRate, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + selectionFlags, + /* language= */ null, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + initializationData, + /* drmInitData= */ null, + /* metadata= */ null); } public static Format createVideoSampleFormat( @@ -197,10 +249,21 @@ public final class Format implements Parcelable { int width, int height, float frameRate, - List initializationData, + @Nullable List initializationData, @Nullable DrmInitData drmInitData) { - return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, initializationData, NO_VALUE, NO_VALUE, drmInitData); + return createVideoSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + initializationData, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + drmInitData); } public static Format createVideoSampleFormat( @@ -212,13 +275,26 @@ public final class Format implements Parcelable { int width, int height, float frameRate, - List initializationData, + @Nullable List initializationData, int rotationDegrees, float pixelWidthHeightRatio, @Nullable DrmInitData drmInitData) { - return createVideoSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, initializationData, rotationDegrees, pixelWidthHeightRatio, null, - NO_VALUE, null, drmInitData); + return createVideoSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + initializationData, + rotationDegrees, + pixelWidthHeightRatio, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + drmInitData); } public static Format createVideoSampleFormat( @@ -230,21 +306,46 @@ public final class Format implements Parcelable { int width, int height, float frameRate, - List initializationData, + @Nullable List initializationData, int rotationDegrees, float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode, @Nullable ColorInfo colorInfo, @Nullable DrmInitData drmInitData) { - return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, width, height, - frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, 0, null, NO_VALUE, - OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, null); + return new Format( + id, + /* label= */ null, + /* containerMimeType= */ null, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + /* selectionFlags= */ 0, + /* language= */ null, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + initializationData, + drmInitData, + /* metadata= */ null); } // Audio. + @Deprecated public static Format createAudioContainerFormat( @Nullable String id, @Nullable String containerMimeType, @@ -253,13 +354,63 @@ public final class Format implements Parcelable { int bitrate, int channelCount, int sampleRate, - List initializationData, + @Nullable List initializationData, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, - NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, - initializationData, null, null); + return createAudioContainerFormat( + id, + /* label= */ null, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + channelCount, + sampleRate, + initializationData, + selectionFlags, + language); + } + + public static Format createAudioContainerFormat( + @Nullable String id, + @Nullable String label, + @Nullable String containerMimeType, + @Nullable String sampleMimeType, + @Nullable String codecs, + int bitrate, + int channelCount, + int sampleRate, + @Nullable List initializationData, + @C.SelectionFlags int selectionFlags, + @Nullable String language) { + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + channelCount, + sampleRate, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + selectionFlags, + language, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + initializationData, + /* drmInitData= */ null, + /* metadata= */ null); } public static Format createAudioSampleFormat( @@ -270,12 +421,23 @@ public final class Format implements Parcelable { int maxInputSize, int channelCount, int sampleRate, - List initializationData, + @Nullable List initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, - sampleRate, NO_VALUE, initializationData, drmInitData, selectionFlags, language); + return createAudioSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + channelCount, + sampleRate, + /* pcmEncoding= */ NO_VALUE, + initializationData, + drmInitData, + selectionFlags, + language); } public static Format createAudioSampleFormat( @@ -287,13 +449,26 @@ public final class Format implements Parcelable { int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, - List initializationData, + @Nullable List initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return createAudioSampleFormat(id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, - sampleRate, pcmEncoding, NO_VALUE, NO_VALUE, initializationData, drmInitData, - selectionFlags, language, null); + return createAudioSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + channelCount, + sampleRate, + pcmEncoding, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + initializationData, + drmInitData, + selectionFlags, + language, + /* metadata= */ null); } public static Format createAudioSampleFormat( @@ -307,19 +482,44 @@ public final class Format implements Parcelable { @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, - List initializationData, + @Nullable List initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language, @Nullable Metadata metadata) { - return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, pcmEncoding, - encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, - initializationData, drmInitData, metadata); + return new Format( + id, + /* label= */ null, + /* containerMimeType= */ null, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + initializationData, + drmInitData, + metadata); } // Text. + @Deprecated public static Format createTextContainerFormat( @Nullable String id, @Nullable String containerMimeType, @@ -328,12 +528,41 @@ public final class Format implements Parcelable { int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate, - selectionFlags, language, NO_VALUE); + return createTextContainerFormat( + id, + /* label= */ null, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language); } public static Format createTextContainerFormat( @Nullable String id, + @Nullable String label, + @Nullable String containerMimeType, + @Nullable String sampleMimeType, + @Nullable String codecs, + int bitrate, + @C.SelectionFlags int selectionFlags, + @Nullable String language) { + return createTextContainerFormat( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language, + /* accessibilityChannel= */ NO_VALUE); + } + + public static Format createTextContainerFormat( + @Nullable String id, + @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, @@ -341,10 +570,34 @@ public final class Format implements Parcelable { @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, selectionFlags, language, accessibilityChannel, - OFFSET_SAMPLE_RELATIVE, null, null, null); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + selectionFlags, + language, + accessibilityChannel, + OFFSET_SAMPLE_RELATIVE, + /* initializationData= */ null, + /* drmInitData= */ null, + /* metadata= */ null); } public static Format createTextSampleFormat( @@ -361,8 +614,17 @@ public final class Format implements Parcelable { @C.SelectionFlags int selectionFlags, @Nullable String language, @Nullable DrmInitData drmInitData) { - return createTextSampleFormat(id, sampleMimeType, null, NO_VALUE, selectionFlags, language, - NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.emptyList()); + return createTextSampleFormat( + id, + sampleMimeType, + /* codecs= */ null, + /* bitrate= */ NO_VALUE, + selectionFlags, + language, + NO_VALUE, + drmInitData, + OFFSET_SAMPLE_RELATIVE, + Collections.emptyList()); } public static Format createTextSampleFormat( @@ -374,8 +636,17 @@ public final class Format implements Parcelable { @Nullable String language, int accessibilityChannel, @Nullable DrmInitData drmInitData) { - return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, - accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.emptyList()); + return createTextSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language, + accessibilityChannel, + drmInitData, + OFFSET_SAMPLE_RELATIVE, + Collections.emptyList()); } public static Format createTextSampleFormat( @@ -387,8 +658,17 @@ public final class Format implements Parcelable { @Nullable String language, @Nullable DrmInitData drmInitData, long subsampleOffsetUs) { - return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, - NO_VALUE, drmInitData, subsampleOffsetUs, Collections.emptyList()); + return createTextSampleFormat( + id, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language, + /* accessibilityChannel= */ NO_VALUE, + drmInitData, + subsampleOffsetUs, + Collections.emptyList()); } public static Format createTextSampleFormat( @@ -402,10 +682,34 @@ public final class Format implements Parcelable { @Nullable DrmInitData drmInitData, long subsampleOffsetUs, List initializationData) { - return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, - initializationData, drmInitData, null); + return new Format( + id, + /* label= */ null, + /* containerMimeType= */ null, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + /* metadata= */ null); } // Image. @@ -416,40 +720,42 @@ public final class Format implements Parcelable { @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, - List initializationData, + @Nullable List initializationData, @Nullable String language, @Nullable DrmInitData drmInitData) { return new Format( id, - null, + /* label= */ null, + /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, - NO_VALUE, - NO_VALUE, - NO_VALUE, - NO_VALUE, - NO_VALUE, - NO_VALUE, - null, - NO_VALUE, - null, - NO_VALUE, - NO_VALUE, - NO_VALUE, - NO_VALUE, - NO_VALUE, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, selectionFlags, language, - NO_VALUE, + /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, - null); + /* metadata=*/ null); } // Generic. + @Deprecated public static Format createContainerFormat( @Nullable String id, @Nullable String containerMimeType, @@ -458,17 +764,86 @@ public final class Format implements Parcelable { int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null, - null); + return createContainerFormat( + id, + /* label= */ null, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language); + } + + public static Format createContainerFormat( + @Nullable String id, + @Nullable String label, + @Nullable String containerMimeType, + @Nullable String sampleMimeType, + @Nullable String codecs, + int bitrate, + @C.SelectionFlags int selectionFlags, + @Nullable String language) { + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + selectionFlags, + language, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + /* initializationData= */ null, + /* drmInitData= */ null, + /* metadata= */ null); } public static Format createSampleFormat( @Nullable String id, @Nullable String sampleMimeType, long subsampleOffsetUs) { - return new Format(id, null, sampleMimeType, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, 0, null, NO_VALUE, subsampleOffsetUs, null, null, null); + return new Format( + id, + /* label= */ null, + /* containerMimeType= */ null, + sampleMimeType, + /* codecs= */ null, + /* bitrate= */ NO_VALUE, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + /* selectionFlags= */ 0, + /* language= */ null, + /* accessibilityChannel= */ NO_VALUE, + subsampleOffsetUs, + /* initializationData= */ null, + /* drmInitData= */ null, + /* metadata= */ null); } public static Format createSampleFormat( @@ -477,13 +852,39 @@ public final class Format implements Parcelable { @Nullable String codecs, int bitrate, @Nullable DrmInitData drmInitData) { - return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, drmInitData, null); + return new Format( + id, + /* label= */ null, + /* containerMimeType= */ null, + sampleMimeType, + codecs, + bitrate, + /* maxInputSize= */ NO_VALUE, + /* width= */ NO_VALUE, + /* height= */ NO_VALUE, + /* frameRate= */ NO_VALUE, + /* rotationDegrees= */ NO_VALUE, + /* pixelWidthHeightRatio= */ NO_VALUE, + /* projectionData= */ null, + /* stereoMode= */ NO_VALUE, + /* colorInfo= */ null, + /* channelCount= */ NO_VALUE, + /* sampleRate= */ NO_VALUE, + /* pcmEncoding= */ NO_VALUE, + /* encoderDelay= */ NO_VALUE, + /* encoderPadding= */ NO_VALUE, + /* selectionFlags= */ 0, + /* language= */ null, + /* accessibilityChannel= */ NO_VALUE, + OFFSET_SAMPLE_RELATIVE, + /* initializationData= */ null, + drmInitData, + /* metadata= */ null); } /* package */ Format( @Nullable String id, + @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, @@ -510,6 +911,7 @@ public final class Format implements Parcelable { @Nullable DrmInitData drmInitData, @Nullable Metadata metadata) { this.id = id; + this.label = label; this.containerMimeType = containerMimeType; this.sampleMimeType = sampleMimeType; this.codecs = codecs; @@ -533,8 +935,8 @@ public final class Format implements Parcelable { this.language = language; this.accessibilityChannel = accessibilityChannel; this.subsampleOffsetUs = subsampleOffsetUs; - this.initializationData = initializationData == null ? Collections.emptyList() - : initializationData; + this.initializationData = + initializationData == null ? Collections.emptyList() : initializationData; this.drmInitData = drmInitData; this.metadata = metadata; } @@ -542,6 +944,7 @@ public final class Format implements Parcelable { @SuppressWarnings("ResourceType") /* package */ Format(Parcel in) { id = in.readString(); + label = in.readString(); containerMimeType = in.readString(); sampleMimeType = in.readString(); codecs = in.readString(); @@ -575,23 +978,70 @@ public final class Format implements Parcelable { } public Format copyWithMaxInputSize(int maxInputSize) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithContainerInfo( @Nullable String id, + @Nullable String label, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @@ -599,11 +1049,34 @@ public final class Format implements Parcelable { int height, @C.SelectionFlags int selectionFlags, @Nullable String language) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } @SuppressWarnings("ReferenceEquality") @@ -612,51 +1085,193 @@ public final class Format implements Parcelable { // No need to copy from ourselves. return this; } + + int trackType = MimeTypes.getTrackType(sampleMimeType); + + // Use manifest value only. String id = manifestFormat.id; - String codecs = this.codecs == null ? manifestFormat.codecs : this.codecs; + + // Prefer manifest values, but fill in from sample format if missing. + String label = manifestFormat.label != null ? manifestFormat.label : this.label; + String language = this.language; + if ((trackType == C.TRACK_TYPE_TEXT || trackType == C.TRACK_TYPE_AUDIO) + && manifestFormat.language != null) { + language = manifestFormat.language; + } + + // Prefer sample format values, but fill in from manifest if missing. int bitrate = this.bitrate == NO_VALUE ? manifestFormat.bitrate : this.bitrate; - float frameRate = this.frameRate == NO_VALUE ? manifestFormat.frameRate : this.frameRate; - @C.SelectionFlags int selectionFlags = this.selectionFlags | manifestFormat.selectionFlags; - String language = this.language == null ? manifestFormat.language : this.language; + String codecs = this.codecs; + if (codecs == null) { + // The manifest format may be muxed, so filter only codecs of this format's type. If we still + // have more than one codec then we're unable to uniquely identify which codec to fill in. + String codecsOfType = Util.getCodecsOfType(manifestFormat.codecs, trackType); + if (Util.splitCodecs(codecsOfType).length == 1) { + codecs = codecsOfType; + } + } + float frameRate = this.frameRate; + if (frameRate == NO_VALUE && trackType == C.TRACK_TYPE_VIDEO) { + frameRate = manifestFormat.frameRate; + } + + // Merge manifest and sample format values. + @C.SelectionFlags int selectionFlags = this.selectionFlags | manifestFormat.selectionFlags; DrmInitData drmInitData = DrmInitData.createSessionCreationData(manifestFormat.drmInitData, this.drmInitData); - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithDrmInitData(@Nullable DrmInitData drmInitData) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithMetadata(@Nullable Metadata metadata) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } public Format copyWithRotationDegrees(int rotationDegrees) { - return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, - height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, - colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, - selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, - drmInitData, metadata); + return new Format( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + maxInputSize, + width, + height, + frameRate, + rotationDegrees, + pixelWidthHeightRatio, + projectionData, + stereoMode, + colorInfo, + channelCount, + sampleRate, + pcmEncoding, + encoderDelay, + encoderPadding, + selectionFlags, + language, + accessibilityChannel, + subsampleOffsetUs, + initializationData, + drmInitData, + metadata); } /** @@ -669,9 +1284,32 @@ public final class Format implements Parcelable { @Override public String toString() { - return "Format(" + id + ", " + containerMimeType + ", " + sampleMimeType + ", " + bitrate + ", " - + language + ", [" + width + ", " + height + ", " + frameRate + "]" - + ", [" + channelCount + ", " + sampleRate + "])"; + return "Format(" + + id + + ", " + + label + + ", " + + containerMimeType + + ", " + + sampleMimeType + + ", " + + codecs + + ", " + + bitrate + + ", " + + language + + ", [" + + width + + ", " + + height + + ", " + + frameRate + + "]" + + ", [" + + channelCount + + ", " + + sampleRate + + "])"; } @Override @@ -721,6 +1359,7 @@ public final class Format implements Parcelable { && subsampleOffsetUs == other.subsampleOffsetUs && selectionFlags == other.selectionFlags && Util.areEqual(id, other.id) + && Util.areEqual(label, other.label) && Util.areEqual(language, other.language) && accessibilityChannel == other.accessibilityChannel && Util.areEqual(containerMimeType, other.containerMimeType) @@ -767,6 +1406,9 @@ public final class Format implements Parcelable { if (format.bitrate != Format.NO_VALUE) { builder.append(", bitrate=").append(format.bitrate); } + if (format.codecs != null) { + builder.append(", codecs=").append(format.codecs); + } if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) { builder.append(", res=").append(format.width).append("x").append(format.height); } @@ -782,6 +1424,9 @@ public final class Format implements Parcelable { if (format.language != null) { builder.append(", language=").append(format.language); } + if (format.label != null) { + builder.append(", label=").append(format.label); + } return builder.toString(); } @@ -795,6 +1440,7 @@ public final class Format implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(id); + dest.writeString(label); dest.writeString(containerMimeType); dest.writeString(sampleMimeType); dest.writeString(codecs); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/FormatHolder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/FormatHolder.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/FormatHolder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/FormatHolder.java index b00dea7f4..8c7ba1eb9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/FormatHolder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/FormatHolder.java @@ -13,16 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; + +import android.support.annotation.Nullable; /** * Holds a {@link Format}. */ public final class FormatHolder { - /** - * The held {@link Format}. - */ - public Format format; - + /** The held {@link Format}. */ + public @Nullable Format format; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/IllegalSeekPositionException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/IllegalSeekPositionException.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/IllegalSeekPositionException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/IllegalSeekPositionException.java index b6de1d66b..baa1cf3f7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/IllegalSeekPositionException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/IllegalSeekPositionException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; /** * Thrown when an attempt is made to seek to a position that does not exist in the player's diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/LoadControl.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/LoadControl.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/LoadControl.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/LoadControl.java index 7c1497b04..80be0b9e7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/LoadControl.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/LoadControl.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.upstream.Allocator; /** * Controls buffering of media. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodHolder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodHolder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java index ca1b4df50..d9dde9d4e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodHolder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.util.Log; -import org.telegram.messenger.exoplayer2.source.ClippingMediaPeriod; -import org.telegram.messenger.exoplayer2.source.EmptySampleStream; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.source.ClippingMediaPeriod; +import com.google.android.exoplayer2.source.EmptySampleStream; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectorResult; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.Assertions; /** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */ /* package */ final class MediaPeriodHolder { @@ -82,13 +82,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions; sampleStreams = new SampleStream[rendererCapabilities.length]; mayRetainStreamFlags = new boolean[rendererCapabilities.length]; MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator); - if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) { mediaPeriod = new ClippingMediaPeriod( mediaPeriod, /* enableInitialDiscontinuity= */ true, /* startUs= */ 0, - info.endPositionUs); + info.id.endPositionUs); } this.mediaPeriod = mediaPeriod; } @@ -127,7 +127,8 @@ import org.telegram.messenger.exoplayer2.util.Assertions; if (!prepared) { return info.startPositionUs; } - long bufferedPositionUs = mediaPeriod.getBufferedPositionUs(); + long bufferedPositionUs = + hasEnabledTracks ? mediaPeriod.getBufferedPositionUs() : C.TIME_END_OF_SOURCE; return bufferedPositionUs == C.TIME_END_OF_SOURCE && convertEosToDuration ? info.durationUs : bufferedPositionUs; @@ -218,7 +219,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions; public void release() { updatePeriodTrackSelectorResult(null); try { - if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) { mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod); } else { mediaSource.releasePeriod(mediaPeriod); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java index 801146917..b887e8222 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; /** Stores the information required to load and play a {@link MediaPeriod}. */ /* package */ final class MediaPeriodInfo { @@ -25,18 +25,13 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; public final MediaPeriodId id; /** The start position of the media to play within the media period, in microseconds. */ public final long startPositionUs; - /** - * The end position of the media to play within the media period, in microseconds, or {@link - * C#TIME_END_OF_SOURCE} if the end position is the end of the media period. - */ - public final long endPositionUs; /** * If this is an ad, the position to play in the next content media period. {@link C#TIME_UNSET} * otherwise. */ public final long contentPositionUs; /** - * The duration of the media period, like {@link #endPositionUs} but with {@link + * The duration of the media period, like {@link MediaPeriodId#endPositionUs} but with {@link * C#TIME_END_OF_SOURCE} resolved to the timeline period duration. May be {@link C#TIME_UNSET} if * the end position is not known. */ @@ -55,14 +50,12 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; MediaPeriodInfo( MediaPeriodId id, long startPositionUs, - long endPositionUs, long contentPositionUs, long durationUs, boolean isLastInTimelinePeriod, boolean isFinal) { this.id = id; this.startPositionUs = startPositionUs; - this.endPositionUs = endPositionUs; this.contentPositionUs = contentPositionUs; this.durationUs = durationUs; this.isLastInTimelinePeriod = isLastInTimelinePeriod; @@ -77,7 +70,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; return new MediaPeriodInfo( id.copyWithPeriodIndex(periodIndex), startPositionUs, - endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, @@ -89,7 +81,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; return new MediaPeriodInfo( id, startPositionUs, - endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodQueue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodQueue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java index 3c05aa157..e9be2d985 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/MediaPeriodQueue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; import android.util.Pair; -import org.telegram.messenger.exoplayer2.Player.RepeatMode; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.Player.RepeatMode; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.Assertions; /** * Holds a queue of media periods, from the currently playing media period at the front to the @@ -47,17 +47,18 @@ import org.telegram.messenger.exoplayer2.util.Assertions; private Timeline timeline; private @RepeatMode int repeatMode; private boolean shuffleModeEnabled; - private MediaPeriodHolder playing; - private MediaPeriodHolder reading; - private MediaPeriodHolder loading; + private @Nullable MediaPeriodHolder playing; + private @Nullable MediaPeriodHolder reading; + private @Nullable MediaPeriodHolder loading; private int length; - private Object oldFrontPeriodUid; + private @Nullable Object oldFrontPeriodUid; private long oldFrontPeriodWindowSequenceNumber; /** Creates a new media period queue. */ public MediaPeriodQueue() { period = new Timeline.Period(); window = new Timeline.Window(); + timeline = Timeline.EMPTY; } /** @@ -228,11 +229,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions; reading = playing.next; } playing.release(); - playing = playing.next; length--; if (length == 0) { loading = null; + oldFrontPeriodUid = playing.uid; + oldFrontPeriodWindowSequenceNumber = playing.info.id.windowSequenceNumber; } + playing = playing.next; } else { playing = loading; reading = loading; @@ -312,7 +315,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions; } else { // Check this period holder still follows the previous one, based on the new timeline. if (periodIndex == C.INDEX_UNSET - || !periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { + || !periodHolder.uid.equals(timeline.getUidOfPeriod(periodIndex))) { // The holder uid is inconsistent with the new timeline. return !removeAfter(previousPeriodHolder); } @@ -389,7 +392,12 @@ import org.telegram.messenger.exoplayer2.util.Assertions; timeline.getPeriod(periodIndex, period); int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); if (adGroupIndex == C.INDEX_UNSET) { - return new MediaPeriodId(periodIndex, windowSequenceNumber); + int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs); + long endPositionUs = + nextAdGroupIndex == C.INDEX_UNSET + ? C.TIME_END_OF_SOURCE + : period.getAdGroupTimeUs(nextAdGroupIndex); + return new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs); } else { int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex); return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); @@ -448,7 +456,6 @@ import org.telegram.messenger.exoplayer2.util.Assertions; private boolean canKeepMediaPeriodHolder(MediaPeriodHolder periodHolder, MediaPeriodInfo info) { MediaPeriodInfo periodHolderInfo = periodHolder.info; return periodHolderInfo.startPositionUs == info.startPositionUs - && periodHolderInfo.endPositionUs == info.endPositionUs && periodHolderInfo.id.equals(info.id); } @@ -591,14 +598,14 @@ import org.telegram.messenger.exoplayer2.util.Assertions; mediaPeriodInfo.contentPositionUs, currentPeriodId.windowSequenceNumber); } - } else if (mediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) { + } else if (mediaPeriodInfo.id.endPositionUs != C.TIME_END_OF_SOURCE) { // Play the next ad group if it's available. - int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.endPositionUs); + int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.id.endPositionUs); if (nextAdGroupIndex == C.INDEX_UNSET) { // The next ad group can't be played. Play content from the ad group position instead. return getMediaPeriodInfoForContent( currentPeriodId.periodIndex, - mediaPeriodInfo.endPositionUs, + mediaPeriodInfo.id.endPositionUs, currentPeriodId.windowSequenceNumber); } int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex); @@ -608,7 +615,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions; currentPeriodId.periodIndex, nextAdGroupIndex, adIndexInAdGroup, - mediaPeriodInfo.endPositionUs, + mediaPeriodInfo.id.endPositionUs, currentPeriodId.windowSequenceNumber); } else { // Check if the postroll ad should be played. @@ -637,18 +644,18 @@ import org.telegram.messenger.exoplayer2.util.Assertions; private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) { long startPositionUs = info.startPositionUs; - long endPositionUs = info.endPositionUs; - boolean isLastInPeriod = isLastInPeriod(newId, endPositionUs); + boolean isLastInPeriod = isLastInPeriod(newId); boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod); timeline.getPeriod(newId.periodIndex, period); long durationUs = newId.isAd() ? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup) - : (endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs); + : (newId.endPositionUs == C.TIME_END_OF_SOURCE + ? period.getDurationUs() + : newId.endPositionUs); return new MediaPeriodInfo( newId, startPositionUs, - endPositionUs, info.contentPositionUs, durationUs, isLastInPeriod, @@ -681,7 +688,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions; long windowSequenceNumber) { MediaPeriodId id = new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); - boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); + boolean isLastInPeriod = isLastInPeriod(id); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); long durationUs = timeline @@ -694,7 +701,6 @@ import org.telegram.messenger.exoplayer2.util.Assertions; return new MediaPeriodInfo( id, startPositionUs, - C.TIME_END_OF_SOURCE, contentPositionUs, durationUs, isLastInPeriod, @@ -703,21 +709,22 @@ import org.telegram.messenger.exoplayer2.util.Assertions; private MediaPeriodInfo getMediaPeriodInfoForContent( int periodIndex, long startPositionUs, long windowSequenceNumber) { - MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber); - timeline.getPeriod(id.periodIndex, period); int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); - long endUs = + long endPositionUs = nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_END_OF_SOURCE : period.getAdGroupTimeUs(nextAdGroupIndex); - boolean isLastInPeriod = isLastInPeriod(id, endUs); + MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs); + timeline.getPeriod(id.periodIndex, period); + boolean isLastInPeriod = isLastInPeriod(id); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); - long durationUs = endUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endUs; + long durationUs = + endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs; return new MediaPeriodInfo( - id, startPositionUs, endUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline); + id, startPositionUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline); } - private boolean isLastInPeriod(MediaPeriodId id, long endPositionUs) { + private boolean isLastInPeriod(MediaPeriodId id) { int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount(); if (adGroupCount == 0) { return true; @@ -727,7 +734,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions; boolean isAd = id.isAd(); if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) { // There's no postroll ad. - return !isAd && endPositionUs == C.TIME_END_OF_SOURCE; + return !isAd && id.endPositionUs == C.TIME_END_OF_SOURCE; } int postrollAdCount = period.getAdCountInAdGroup(lastAdGroupIndex); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/NoSampleRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/NoSampleRenderer.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/NoSampleRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/NoSampleRenderer.java index 6717ca488..593d3d1fc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/NoSampleRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/NoSampleRenderer.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MediaClock; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ParserException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ParserException.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ParserException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ParserException.java index 36a2ed4b8..e0cae0cf3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ParserException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ParserException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java new file mode 100755 index 000000000..b556db6be --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectorResult; + +/** + * Information about an ongoing playback. + */ +/* package */ final class PlaybackInfo { + + /** + * Dummy media period id used while the timeline is empty and no period id is specified. This id + * is used when playback infos are created with {@link #createDummy(long, TrackSelectorResult)}. + */ + public static final MediaPeriodId DUMMY_MEDIA_PERIOD_ID = new MediaPeriodId(/* periodIndex= */ 0); + + /** The current {@link Timeline}. */ + public final Timeline timeline; + /** The current manifest. */ + public final @Nullable Object manifest; + /** The {@link MediaPeriodId} of the currently playing media period in the {@link #timeline}. */ + public final MediaPeriodId periodId; + /** + * The start position at which playback started in {@link #periodId} relative to the start of the + * associated period in the {@link #timeline}, in microseconds. + */ + public final long startPositionUs; + /** + * If {@link #periodId} refers to an ad, the position of the suspended content relative to the + * start of the associated period in the {@link #timeline}, in microseconds. {@link C#TIME_UNSET} + * if {@link #periodId} does not refer to an ad. + */ + public final long contentPositionUs; + /** The current playback state. One of the {@link Player}.STATE_ constants. */ + public final int playbackState; + /** Whether the player is currently loading. */ + public final boolean isLoading; + /** The currently available track groups. */ + public final TrackGroupArray trackGroups; + /** The result of the current track selection. */ + public final TrackSelectorResult trackSelectorResult; + /** The {@link MediaPeriodId} of the currently loading media period in the {@link #timeline}. */ + public final MediaPeriodId loadingMediaPeriodId; + + /** + * Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start + * of the associated period in the {@link #timeline}, in microseconds. + */ + public volatile long bufferedPositionUs; + /** + * Total duration of buffered media from {@link #positionUs} to {@link #bufferedPositionUs} + * including all ads. + */ + public volatile long totalBufferedDurationUs; + /** + * Current playback position in {@link #periodId} relative to the start of the associated period + * in the {@link #timeline}, in microseconds. + */ + public volatile long positionUs; + + /** + * Creates empty dummy playback info which can be used for masking as long as no real playback + * info is available. + * + * @param startPositionUs The start position at which playback should start, in microseconds. + * @param emptyTrackSelectorResult An empty track selector result with null entries for each + * renderer. + * @return A dummy playback info. + */ + public static PlaybackInfo createDummy( + long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) { + return new PlaybackInfo( + Timeline.EMPTY, + /* manifest= */ null, + DUMMY_MEDIA_PERIOD_ID, + startPositionUs, + /* contentPositionUs =*/ C.TIME_UNSET, + Player.STATE_IDLE, + /* isLoading= */ false, + TrackGroupArray.EMPTY, + emptyTrackSelectorResult, + DUMMY_MEDIA_PERIOD_ID, + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); + } + + public PlaybackInfo( + Timeline timeline, + @Nullable Object manifest, + MediaPeriodId periodId, + long startPositionUs, + long contentPositionUs, + int playbackState, + boolean isLoading, + TrackGroupArray trackGroups, + TrackSelectorResult trackSelectorResult, + MediaPeriodId loadingMediaPeriodId, + long bufferedPositionUs, + long totalBufferedDurationUs, + long positionUs) { + this.timeline = timeline; + this.manifest = manifest; + this.periodId = periodId; + this.startPositionUs = startPositionUs; + this.contentPositionUs = contentPositionUs; + this.playbackState = playbackState; + this.isLoading = isLoading; + this.trackGroups = trackGroups; + this.trackSelectorResult = trackSelectorResult; + this.loadingMediaPeriodId = loadingMediaPeriodId; + this.bufferedPositionUs = bufferedPositionUs; + this.totalBufferedDurationUs = totalBufferedDurationUs; + this.positionUs = positionUs; + } + + public PlaybackInfo fromNewPosition( + MediaPeriodId periodId, long startPositionUs, long contentPositionUs) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + periodId.isAd() ? contentPositionUs : C.TIME_UNSET, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + periodId, + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); + } + + public PlaybackInfo copyWithPeriodIndex(int periodIndex) { + return new PlaybackInfo( + timeline, + manifest, + periodId.copyWithPeriodIndex(periodIndex), + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } + + public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } + + public PlaybackInfo copyWithPlaybackState(int playbackState) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } + + public PlaybackInfo copyWithIsLoading(boolean isLoading) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } + + public PlaybackInfo copyWithTrackInfo( + TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } + + public PlaybackInfo copyWithLoadingMediaPeriodId(MediaPeriodId loadingMediaPeriodId) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackParameters.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackParameters.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java index 9e9a576a2..6f2db4ff5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackParameters.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; /** * The parameters that apply to playback. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackPreparer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackPreparer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java index e0cf0c804..8ff7f5040 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackPreparer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; /** Called to prepare a playback. */ public interface PlaybackPreparer { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Player.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Player.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Player.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/Player.java index accf54879..589fde6a2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Player.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Player.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Looper; import android.support.annotation.IntDef; @@ -22,10 +22,13 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.TextureView; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.text.TextOutput; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.video.VideoListener; +import com.google.android.exoplayer2.audio.AudioAttributes; +import com.google.android.exoplayer2.audio.AudioListener; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.text.TextOutput; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.VideoListener; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -50,6 +53,58 @@ import java.lang.annotation.RetentionPolicy; */ public interface Player { + /** The audio component of a {@link Player}. */ + interface AudioComponent { + + /** + * Adds a listener to receive audio events. + * + * @param listener The listener to register. + */ + void addAudioListener(AudioListener listener); + + /** + * Removes a listener of audio events. + * + * @param listener The listener to unregister. + */ + void removeAudioListener(AudioListener listener); + + /** + * Sets the attributes for audio playback, used by the underlying audio track. If not set, the + * default audio attributes will be used. They are suitable for general media playback. + * + *

    Setting the audio attributes during playback may introduce a short gap in audio output as + * the audio track is recreated. A new audio session id will also be generated. + * + *

    If tunneling is enabled by the track selector, the specified audio attributes will be + * ignored, but they will take effect if audio is later played without tunneling. + * + *

    If the device is running a build before platform API version 21, audio attributes cannot + * be set directly on the underlying audio track. In this case, the usage will be mapped onto an + * equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}. + * + * @param audioAttributes The attributes to use for audio playback. + */ + void setAudioAttributes(AudioAttributes audioAttributes); + + /** Returns the attributes for audio playback. */ + AudioAttributes getAudioAttributes(); + + /** Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set. */ + int getAudioSessionId(); + + /** + * Sets the audio volume, with 0 being silence and 1 being unity gain. + * + * @param audioVolume The audio volume. + */ + void setVolume(float audioVolume); + + /** Returns the audio volume, with 0 being silence and 1 being unity gain. */ + float getVolume(); + } + /** The video component of a {@link Player}. */ interface VideoComponent { @@ -97,7 +152,7 @@ public interface Player { * * @param surface The {@link Surface}. */ - void setVideoSurface(Surface surface); + void setVideoSurface(@Nullable Surface surface); /** * Clears the {@link Surface} onto which video is being rendered if it matches the one passed. @@ -175,23 +230,25 @@ public interface Player { } /** - * Listener of changes in player state. + * Listener of changes in player state. All methods have no-op default implementations to allow + * selective overrides. */ interface EventListener { /** * Called when the timeline and/or manifest has been refreshed. - *

    - * Note that if the timeline has changed then a position discontinuity may also have occurred. - * For example, the current period index may have changed as a result of periods being added or - * removed from the timeline. This will not be reported via a separate call to + * + *

    Note that if the timeline has changed then a position discontinuity may also have + * occurred. For example, the current period index may have changed as a result of periods being + * added or removed from the timeline. This will not be reported via a separate call to * {@link #onPositionDiscontinuity(int)}. * * @param timeline The latest timeline. Never null, but may be empty. * @param manifest The latest manifest. May be null. * @param reason The {@link TimelineChangeReason} responsible for this timeline change. */ - void onTimelineChanged(Timeline timeline, Object manifest, @TimelineChangeReason int reason); + default void onTimelineChanged( + Timeline timeline, Object manifest, @TimelineChangeReason int reason) {} /** * Called when the available or selected tracks change. @@ -200,46 +257,47 @@ public interface Player { * @param trackSelections The track selections for each renderer. Never null and always of * length {@link #getRendererCount()}, but may contain null elements. */ - void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections); + default void onTracksChanged( + TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {} /** * Called when the player starts or stops loading the source. * * @param isLoading Whether the source is currently being loaded. */ - void onLoadingChanged(boolean isLoading); + default void onLoadingChanged(boolean isLoading) {} /** - * Called when the value returned from either {@link #getPlayWhenReady()} or - * {@link #getPlaybackState()} changes. + * Called when the value returned from either {@link #getPlayWhenReady()} or {@link + * #getPlaybackState()} changes. * * @param playWhenReady Whether playback will proceed when ready. * @param playbackState One of the {@code STATE} constants. */ - void onPlayerStateChanged(boolean playWhenReady, int playbackState); + default void onPlayerStateChanged(boolean playWhenReady, int playbackState) {} /** * Called when the value of {@link #getRepeatMode()} changes. * * @param repeatMode The {@link RepeatMode} used for playback. */ - void onRepeatModeChanged(@RepeatMode int repeatMode); + default void onRepeatModeChanged(@RepeatMode int repeatMode) {} /** * Called when the value of {@link #getShuffleModeEnabled()} changes. * * @param shuffleModeEnabled Whether shuffling of windows is enabled. */ - void onShuffleModeEnabledChanged(boolean shuffleModeEnabled); + default void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {} /** * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE} - * immediately after this method is called. The player instance can still be used, and - * {@link #release()} must still be called on the player should it no longer be required. + * immediately after this method is called. The player instance can still be used, and {@link + * #release()} must still be called on the player should it no longer be required. * * @param error The error. */ - void onPlayerError(ExoPlaybackException error); + default void onPlayerError(ExoPlaybackException error) {} /** * Called when a position discontinuity occurs without a change to the timeline. A position @@ -247,14 +305,14 @@ public interface Player { * transitioning from one period in the timeline to the next), or when the playback position * jumps within the period currently being played (as a result of a seek being performed, or * when the source introduces a discontinuity internally). - *

    - * When a position discontinuity occurs as a result of a change to the timeline this method is - * not called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this + * + *

    When a position discontinuity occurs as a result of a change to the timeline this method + * is not called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this * case. * * @param reason The {@link DiscontinuityReason} responsible for the discontinuity. */ - void onPositionDiscontinuity(@DiscontinuityReason int reason); + default void onPositionDiscontinuity(@DiscontinuityReason int reason) {} /** * Called when the current playback parameters change. The playback parameters may change due to @@ -264,20 +322,21 @@ public interface Player { * * @param playbackParameters The playback parameters. */ - void onPlaybackParametersChanged(PlaybackParameters playbackParameters); + default void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {} /** * Called when all pending seek requests have been processed by the player. This is guaranteed - * to happen after any necessary changes to the player state were reported to - * {@link #onPlayerStateChanged(boolean, int)}. + * to happen after any necessary changes to the player state were reported to {@link + * #onPlayerStateChanged(boolean, int)}. */ - void onSeekProcessed(); - + default void onSeekProcessed() {} } /** - * {@link EventListener} allowing selective overrides. All methods are implemented as no-ops. + * @deprecated Use {@link EventListener} interface directly for selective overrides as all methods + * are implemented as no-op default methods. */ + @Deprecated abstract class DefaultEventListener implements EventListener { @Override @@ -287,60 +346,11 @@ public interface Player { onTimelineChanged(timeline, manifest); } - @Override - public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { - // Do nothing. - } - - @Override - public void onLoadingChanged(boolean isLoading) { - // Do nothing. - } - - @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - // Do nothing. - } - - @Override - public void onRepeatModeChanged(@RepeatMode int repeatMode) { - // Do nothing. - } - - @Override - public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { - // Do nothing. - } - - @Override - public void onPlayerError(ExoPlaybackException error) { - // Do nothing. - } - - @Override - public void onPositionDiscontinuity(@DiscontinuityReason int reason) { - // Do nothing. - } - - @Override - public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { - // Do nothing. - } - - @Override - public void onSeekProcessed() { - // Do nothing. - } - - /** - * @deprecated Use {@link DefaultEventListener#onTimelineChanged(Timeline, Object, int)} - * instead. - */ + /** @deprecated Use {@link EventListener#onTimelineChanged(Timeline, Object, int)} instead. */ @Deprecated public void onTimelineChanged(Timeline timeline, Object manifest) { // Do nothing. } - } /** @@ -428,6 +438,10 @@ public interface Player { */ int TIMELINE_CHANGE_REASON_DYNAMIC = 2; + /** Returns the component of this player for audio output, or null if audio is not supported. */ + @Nullable + AudioComponent getAudioComponent(); + /** Returns the component of this player for video output, or null if video is not supported. */ @Nullable VideoComponent getVideoComponent(); @@ -678,23 +692,27 @@ public interface Player { */ long getDuration(); - /** - * Returns the playback position in the current window, in milliseconds. - */ + /** Returns the playback position in the current content window or ad, in milliseconds. */ long getCurrentPosition(); /** - * Returns an estimate of the position in the current window up to which data is buffered, in - * milliseconds. + * Returns an estimate of the position in the current content window or ad up to which data is + * buffered, in milliseconds. */ long getBufferedPosition(); /** - * Returns an estimate of the percentage in the current window up to which data is buffered, or 0 - * if no estimate is available. + * Returns an estimate of the percentage in the current content window or ad up to which data is + * buffered, or 0 if no estimate is available. */ int getBufferedPercentage(); + /** + * Returns an estimate of the total buffered duration from the current position, in milliseconds. + * This includes pre-buffered data for subsequent ads and windows. + */ + long getTotalBufferedDuration(); + /** * Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is * empty. @@ -735,4 +753,10 @@ public interface Player { */ long getContentPosition(); + /** + * If {@link #isPlayingAd()} returns {@code true}, returns an estimate of the content position in + * the current content window up to which data is buffered, in milliseconds. If there is no ad + * playing, the returned position is the same as that returned by {@link #getBufferedPosition()}. + */ + long getContentBufferedPosition(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlayerMessage.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlayerMessage.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlayerMessage.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/PlayerMessage.java index ee6fdb5b4..2c7aee834 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlayerMessage.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/PlayerMessage.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; /** * Defines a player message which can be sent with a {@link Sender} and received by a {@link diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Renderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Renderer.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Renderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/Renderer.java index 0451d71ac..c29017856 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Renderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Renderer.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.util.MediaClock; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -192,6 +192,18 @@ public interface Renderer extends PlayerMessage.Target { */ void resetPosition(long positionUs) throws ExoPlaybackException; + /** + * Sets the operating rate of this renderer, where 1 is the default rate, 2 is twice the default + * rate, 0.5 is half the default rate and so on. The operating rate is a hint to the renderer of + * the speed at which playback will proceed, and may be used for resource planning. + * + *

    The default implementation is a no-op. + * + * @param operatingRate The operating rate. + * @throws ExoPlaybackException If an error occurs handling the operating rate. + */ + default void setOperatingRate(float operatingRate) throws ExoPlaybackException {}; + /** * Incrementally renders the {@link SampleStream}. *

    diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererCapabilities.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererCapabilities.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java index ec07aeb5d..de0d48138 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererCapabilities.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.MimeTypes; /** * Defines the capabilities of a {@link Renderer}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererConfiguration.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererConfiguration.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererConfiguration.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererConfiguration.java index 15e40cab5..684072efc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RendererConfiguration.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RendererConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RenderersFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RenderersFactory.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RenderersFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/RenderersFactory.java index eb61fbfe5..e22189847 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/RenderersFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/RenderersFactory.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; -import org.telegram.messenger.exoplayer2.text.TextOutput; -import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.metadata.MetadataOutput; +import com.google.android.exoplayer2.text.TextOutput; +import com.google.android.exoplayer2.video.VideoRendererEventListener; /** * Builds {@link Renderer} instances for use by a {@link SimpleExoPlayer}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SeekParameters.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SeekParameters.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SeekParameters.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/SeekParameters.java index 769f564f1..ca0433f96 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SeekParameters.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SeekParameters.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; /** * Parameters that apply to seeking. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SimpleExoPlayer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SimpleExoPlayer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 18b737a12..450207ba6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/SimpleExoPlayer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.annotation.TargetApi; +import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.media.MediaCodec; import android.media.PlaybackParams; @@ -27,25 +28,27 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.TextureView; -import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector; -import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener; -import org.telegram.messenger.exoplayer2.audio.AudioAttributes; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.TextOutput; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; +import com.google.android.exoplayer2.analytics.AnalyticsCollector; +import com.google.android.exoplayer2.analytics.AnalyticsListener; +import com.google.android.exoplayer2.audio.AudioAttributes; +import com.google.android.exoplayer2.audio.AudioListener; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataOutput; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.TextOutput; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -56,11 +59,12 @@ import java.util.concurrent.CopyOnWriteArraySet; * be obtained from {@link ExoPlayerFactory}. */ @TargetApi(16) -public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player.TextComponent { +public class SimpleExoPlayer + implements ExoPlayer, Player.AudioComponent, Player.VideoComponent, Player.TextComponent { - /** @deprecated Use {@link org.telegram.messenger.exoplayer2.video.VideoListener}. */ + /** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */ @Deprecated - public interface VideoListener extends org.telegram.messenger.exoplayer2.video.VideoListener {} + public interface VideoListener extends com.google.android.exoplayer2.video.VideoListener {} private static final String TAG = "SimpleExoPlayer"; @@ -69,12 +73,14 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player private final ExoPlayer player; private final Handler eventHandler; private final ComponentListener componentListener; - private final CopyOnWriteArraySet + private final CopyOnWriteArraySet videoListeners; + private final CopyOnWriteArraySet audioListeners; private final CopyOnWriteArraySet textOutputs; private final CopyOnWriteArraySet metadataOutputs; private final CopyOnWriteArraySet videoDebugListeners; private final CopyOnWriteArraySet audioDebugListeners; + private final BandwidthMeter bandwidthMeter; private final AnalyticsCollector analyticsCollector; private Format videoFormat; @@ -84,10 +90,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player private Surface surface; private boolean ownsSurface; - @C.VideoScalingMode - private int videoScalingMode; + private @C.VideoScalingMode int videoScalingMode; private SurfaceHolder surfaceHolder; private TextureView textureView; + private int surfaceWidth; + private int surfaceHeight; private DecoderCounters videoDecoderCounters; private DecoderCounters audioDecoderCounters; private int audioSessionId; @@ -100,20 +107,27 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * will not be used for DRM protected playbacks. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. */ protected SimpleExoPlayer( RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl, - @Nullable DrmSessionManager drmSessionManager) { + BandwidthMeter bandwidthMeter, + @Nullable DrmSessionManager drmSessionManager, + Looper looper) { this( renderersFactory, trackSelector, loadControl, drmSessionManager, - new AnalyticsCollector.Factory()); + bandwidthMeter, + new AnalyticsCollector.Factory(), + looper); } /** @@ -122,22 +136,29 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player * @param loadControl The {@link LoadControl} that will be used by the instance. * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * will not be used for DRM protected playbacks. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that * will collect and forward all player events. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. */ protected SimpleExoPlayer( RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, - AnalyticsCollector.Factory analyticsCollectorFactory) { + BandwidthMeter bandwidthMeter, + AnalyticsCollector.Factory analyticsCollectorFactory, + Looper looper) { this( renderersFactory, trackSelector, loadControl, drmSessionManager, + bandwidthMeter, analyticsCollectorFactory, - Clock.DEFAULT); + Clock.DEFAULT, + looper); } /** @@ -146,26 +167,32 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player * @param loadControl The {@link LoadControl} that will be used by the instance. * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * will not be used for DRM protected playbacks. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that * will collect and forward all player events. * @param clock The {@link Clock} that will be used by the instance. Should always be {@link * Clock#DEFAULT}, unless the player is being used from a test. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. */ protected SimpleExoPlayer( RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, AnalyticsCollector.Factory analyticsCollectorFactory, - Clock clock) { + Clock clock, + Looper looper) { + this.bandwidthMeter = bandwidthMeter; componentListener = new ComponentListener(); videoListeners = new CopyOnWriteArraySet<>(); + audioListeners = new CopyOnWriteArraySet<>(); textOutputs = new CopyOnWriteArraySet<>(); metadataOutputs = new CopyOnWriteArraySet<>(); videoDebugListeners = new CopyOnWriteArraySet<>(); audioDebugListeners = new CopyOnWriteArraySet<>(); - Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); - eventHandler = new Handler(eventLooper); + eventHandler = new Handler(looper); renderers = renderersFactory.createRenderers( eventHandler, @@ -183,17 +210,26 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player currentCues = Collections.emptyList(); // Build the player and associated objects. - player = createExoPlayerImpl(renderers, trackSelector, loadControl, clock); + player = + createExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper); analyticsCollector = analyticsCollectorFactory.createAnalyticsCollector(player, clock); addListener(analyticsCollector); videoDebugListeners.add(analyticsCollector); + videoListeners.add(analyticsCollector); audioDebugListeners.add(analyticsCollector); + audioListeners.add(analyticsCollector); addMetadataOutput(analyticsCollector); + bandwidthMeter.addEventListener(eventHandler, analyticsCollector); if (drmSessionManager instanceof DefaultDrmSessionManager) { ((DefaultDrmSessionManager) drmSessionManager).addListener(eventHandler, analyticsCollector); } } + @Override + public AudioComponent getAudioComponent() { + return this; + } + @Override public VideoComponent getVideoComponent() { return this; @@ -240,6 +276,8 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player public void setVideoSurface(Surface surface) { removeSurfaceCallbacks(); setVideoSurfaceInternal(surface, false); + int newSurfaceSize = surface == null ? 0 : C.LENGTH_UNSET; + maybeNotifySurfaceSizeChanged(/* width= */ newSurfaceSize, /* height= */ newSurfaceSize); } @Override @@ -255,10 +293,18 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player this.surfaceHolder = surfaceHolder; if (surfaceHolder == null) { setVideoSurfaceInternal(null, false); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); } else { surfaceHolder.addCallback(componentListener); Surface surface = surfaceHolder.getSurface(); - setVideoSurfaceInternal(surface != null && surface.isValid() ? surface : null, false); + if (surface != null && surface.isValid()) { + setVideoSurfaceInternal(surface, /* ownsSurface= */ false); + Rect surfaceSize = surfaceHolder.getSurfaceFrame(); + maybeNotifySurfaceSizeChanged(surfaceSize.width(), surfaceSize.height()); + } else { + setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ false); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); + } } } @@ -289,6 +335,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player needSetSurface = true; if (textureView == null) { setVideoSurfaceInternal(null, true); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); } else { if (textureView.getSurfaceTextureListener() != null) { Log.w(TAG, "Replacing existing SurfaceTextureListener."); @@ -296,7 +343,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player textureView.setSurfaceTextureListener(componentListener); SurfaceTexture surfaceTexture = textureView.isAvailable() ? textureView.getSurfaceTexture() : null; - setVideoSurfaceInternal(surfaceTexture == null ? null : new Surface(surfaceTexture), true); + if (surfaceTexture == null) { + setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); + } else { + setVideoSurfaceInternal(new Surface(surfaceTexture), /* ownsSurface= */ true); + maybeNotifySurfaceSizeChanged(textureView.getWidth(), textureView.getHeight()); + } } } @@ -307,6 +360,68 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player } } + @Override + public void addAudioListener(AudioListener listener) { + audioListeners.add(listener); + } + + @Override + public void removeAudioListener(AudioListener listener) { + audioListeners.remove(listener); + } + + @Override + public void setAudioAttributes(AudioAttributes audioAttributes) { + if (Util.areEqual(this.audioAttributes, audioAttributes)) { + return; + } + this.audioAttributes = audioAttributes; + for (Renderer renderer : renderers) { + if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { + player + .createMessage(renderer) + .setType(C.MSG_SET_AUDIO_ATTRIBUTES) + .setPayload(audioAttributes) + .send(); + } + } + for (AudioListener audioListener : audioListeners) { + audioListener.onAudioAttributesChanged(audioAttributes); + } + } + + @Override + public AudioAttributes getAudioAttributes() { + return audioAttributes; + } + + @Override + public int getAudioSessionId() { + return audioSessionId; + } + + @Override + public void setVolume(float audioVolume) { + audioVolume = Util.constrainValue(audioVolume, /* min= */ 0, /* max= */ 1); + if (this.audioVolume == audioVolume) { + return; + } + this.audioVolume = audioVolume; + for (Renderer renderer : renderers) { + if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { + player.createMessage(renderer).setType(C.MSG_SET_VOLUME).setPayload(audioVolume).send(); + } + } + for (AudioListener audioListener : audioListeners) { + audioListener.onVolumeChanged(audioVolume); + } + } + + @Override + public float getVolume() { + return audioVolume; + } + /** * Sets the stream type for audio playback, used by the underlying audio track. *

    @@ -361,63 +476,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player analyticsCollector.removeListener(listener); } - /** - * Sets the attributes for audio playback, used by the underlying audio track. If not set, the - * default audio attributes will be used. They are suitable for general media playback. - *

    - * Setting the audio attributes during playback may introduce a short gap in audio output as the - * audio track is recreated. A new audio session id will also be generated. - *

    - * If tunneling is enabled by the track selector, the specified audio attributes will be ignored, - * but they will take effect if audio is later played without tunneling. - *

    - * If the device is running a build before platform API version 21, audio attributes cannot be set - * directly on the underlying audio track. In this case, the usage will be mapped onto an - * equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}. - * - * @param audioAttributes The attributes to use for audio playback. - */ - public void setAudioAttributes(AudioAttributes audioAttributes) { - this.audioAttributes = audioAttributes; - for (Renderer renderer : renderers) { - if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { - player - .createMessage(renderer) - .setType(C.MSG_SET_AUDIO_ATTRIBUTES) - .setPayload(audioAttributes) - .send(); - } - } - } - - /** - * Returns the attributes for audio playback. - */ - public AudioAttributes getAudioAttributes() { - return audioAttributes; - } - - /** - * Sets the audio volume, with 0 being silence and 1 being unity gain. - * - * @param audioVolume The audio volume. - */ - public void setVolume(float audioVolume) { - this.audioVolume = audioVolume; - for (Renderer renderer : renderers) { - if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { - player.createMessage(renderer).setType(C.MSG_SET_VOLUME).setPayload(audioVolume).send(); - } - } - } - - /** - * Returns the audio volume, with 0 being silence and 1 being unity gain. - */ - public float getVolume() { - return audioVolume; - } - /** * Sets the {@link PlaybackParams} governing audio playback. * @@ -451,13 +509,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return audioFormat; } - /** - * Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set. - */ - public int getAudioSessionId() { - return audioSessionId; - } - /** * Returns {@link DecoderCounters} for video, or null if no video is being played. */ @@ -473,12 +524,12 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player } @Override - public void addVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) { + public void addVideoListener(com.google.android.exoplayer2.video.VideoListener listener) { videoListeners.add(listener); } @Override - public void removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) { + public void removeVideoListener(com.google.android.exoplayer2.video.VideoListener listener) { videoListeners.remove(listener); } @@ -486,7 +537,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player * Sets a listener to receive video events, removing all existing listeners. * * @param listener The listener. - * @deprecated Use {@link #addVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}. + * @deprecated Use {@link #addVideoListener(com.google.android.exoplayer2.video.VideoListener)}. */ @Deprecated public void setVideoListener(VideoListener listener) { @@ -497,11 +548,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player } /** - * Equivalent to {@link #removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}. + * Equivalent to {@link #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}. * * @param listener The listener to clear. * @deprecated Use {@link - * #removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}. + * #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}. */ @Deprecated public void clearVideoListener(VideoListener listener) { @@ -656,6 +707,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return player.getPlaybackLooper(); } + @Override + public Looper getApplicationLooper() { + return player.getApplicationLooper(); + } + @Override public void addListener(Player.EventListener listener) { player.addListener(listener); @@ -768,6 +824,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player player.setSeekParameters(seekParameters); } + @Override + public SeekParameters getSeekParameters() { + return player.getSeekParameters(); + } + @Override public @Nullable Object getCurrentTag() { return player.getCurrentTag(); @@ -802,6 +863,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player if (mediaSource != null) { mediaSource.removeEventListener(analyticsCollector); } + bandwidthMeter.removeEventListener(analyticsCollector); currentCues = Collections.emptyList(); } @@ -890,6 +952,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return player.getBufferedPercentage(); } + @Override + public long getTotalBufferedDuration() { + return player.getTotalBufferedDuration(); + } + @Override public boolean isCurrentWindowDynamic() { return player.isCurrentWindowDynamic(); @@ -920,6 +987,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return player.getContentPosition(); } + @Override + public long getContentBufferedPosition() { + return player.getContentBufferedPosition(); + } + // Internal methods. /** @@ -928,12 +1000,20 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player * @param renderers The {@link Renderer}s that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance. + * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. * @param clock The {@link Clock} that will be used by this instance. + * @param looper The {@link Looper} which must be used for all calls to the player and which is + * used to call listeners on. * @return A new {@link ExoPlayer} instance. */ protected ExoPlayer createExoPlayerImpl( - Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Clock clock) { - return new ExoPlayerImpl(renderers, trackSelector, loadControl, clock); + Renderer[] renderers, + TrackSelector trackSelector, + LoadControl loadControl, + BandwidthMeter bandwidthMeter, + Clock clock, + Looper looper) { + return new ExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper); } private void removeSurfaceCallbacks() { @@ -979,6 +1059,16 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player this.ownsSurface = ownsSurface; } + private void maybeNotifySurfaceSizeChanged(int width, int height) { + if (width != surfaceWidth || height != surfaceHeight) { + surfaceWidth = width; + surfaceHeight = height; + for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) { + videoListener.onSurfaceSizeChanged(width, height); + } + } + } + private final class ComponentListener implements VideoRendererEventListener, AudioRendererEventListener, TextOutput, MetadataOutput, SurfaceHolder.Callback, TextureView.SurfaceTextureListener { @@ -1020,9 +1110,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) { - videoListener.onVideoSizeChanged(width, height, unappliedRotationDegrees, - pixelWidthHeightRatio); + for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) { + // Prevent duplicate notification if a listener is both a VideoRendererEventListener and + // a VideoListener, as they have the same method signature. + if (!videoDebugListeners.contains(videoListener)) { + videoListener.onVideoSizeChanged( + width, height, unappliedRotationDegrees, pixelWidthHeightRatio); + } } for (VideoRendererEventListener videoDebugListener : videoDebugListeners) { videoDebugListener.onVideoSizeChanged(width, height, unappliedRotationDegrees, @@ -1033,7 +1127,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player @Override public void onRenderedFirstFrame(Surface surface) { if (SimpleExoPlayer.this.surface == surface) { - for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) { + for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) { videoListener.onRenderedFirstFrame(); } } @@ -1063,7 +1157,17 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player @Override public void onAudioSessionId(int sessionId) { + if (audioSessionId == sessionId) { + return; + } audioSessionId = sessionId; + for (AudioListener audioListener : audioListeners) { + // Prevent duplicate notification if a listener is both a AudioRendererEventListener and + // a AudioListener, as they have the same method signature. + if (!audioDebugListeners.contains(audioListener)) { + audioListener.onAudioSessionId(sessionId); + } + } for (AudioRendererEventListener audioDebugListener : audioDebugListeners) { audioDebugListener.onAudioSessionId(sessionId); } @@ -1132,12 +1236,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - // Do nothing. + maybeNotifySurfaceSizeChanged(width, height); } @Override public void surfaceDestroyed(SurfaceHolder holder) { setVideoSurfaceInternal(null, false); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); } // TextureView.SurfaceTextureListener implementation @@ -1148,33 +1253,34 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player setVideoSurfaceInternal(new Surface(surfaceTexture), true); needSetSurface = false; } + maybeNotifySurfaceSizeChanged(width, height); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { - // Do nothing. + maybeNotifySurfaceSizeChanged(width, height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { - for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) { + for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) { if (videoListener.onSurfaceDestroyed(surfaceTexture)) { return false; } } setVideoSurfaceInternal(null, true); + maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); needSetSurface = true; return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) { + for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) { videoListener.onSurfaceTextureUpdated(surfaceTexture); } // Do nothing. } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Timeline.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Timeline.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Timeline.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/Timeline.java index e51f56386..a1a0e9b15 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/Timeline.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2; +package com.google.android.exoplayer2; import android.support.annotation.Nullable; import android.util.Pair; -import org.telegram.messenger.exoplayer2.source.ads.AdPlaybackState; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.source.ads.AdPlaybackState; +import com.google.android.exoplayer2.util.Assertions; /** * A flexible representation of the structure of media. A timeline is able to represent the @@ -520,6 +520,11 @@ public abstract class Timeline { public int getIndexOfPeriod(Object uid) { return C.INDEX_UNSET; } + + @Override + public Object getUidOfPeriod(int periodIndex) { + throw new IndexOutOfBoundsException(); + } }; /** @@ -737,6 +742,17 @@ public abstract class Timeline { return Pair.create(periodIndex, periodPositionUs); } + /** + * Populates a {@link Period} with data for the period with the specified unique identifier. + * + * @param periodUid The unique identifier of the period. + * @param period The {@link Period} to populate. Must not be null. + * @return The populated {@link Period}, for convenience. + */ + public Period getPeriodByUid(Object periodUid, Period period) { + return getPeriod(getIndexOfPeriod(periodUid), period, /* setIds= */ true); + } + /** * Populates a {@link Period} with data for the period at the specified index. Does not populate * {@link Period#id} and {@link Period#uid}. @@ -770,4 +786,11 @@ public abstract class Timeline { */ public abstract int getIndexOfPeriod(Object uid); + /** + * Returns the unique id of the period identified by its index in the timeline. + * + * @param periodIndex The index of the period. + * @return The unique id of the period. + */ + public abstract Object getUidOfPeriod(int periodIndex); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsCollector.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsCollector.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index 554c146fa..d0f92b978 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsCollector.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -13,39 +13,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.analytics; +package com.google.android.exoplayer2.analytics; -import android.net.NetworkInfo; +import android.graphics.SurfaceTexture; import android.support.annotation.Nullable; import android.view.Surface; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.Timeline.Period; -import org.telegram.messenger.exoplayer2.Timeline.Window; -import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener.EventTime; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.upstream.BandwidthMeter; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.Timeline.Period; +import com.google.android.exoplayer2.Timeline.Window; +import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime; +import com.google.android.exoplayer2.audio.AudioAttributes; +import com.google.android.exoplayer2.audio.AudioListener; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataOutput; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.video.VideoListener; +import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Data collector which is able to forward analytics events to {@link AnalyticsListener}s by @@ -58,7 +62,9 @@ public class AnalyticsCollector VideoRendererEventListener, MediaSourceEventListener, BandwidthMeter.EventListener, - DefaultDrmSessionEventListener { + DefaultDrmSessionEventListener, + VideoListener, + AudioListener { /** Factory for an analytics collector. */ public static class Factory { @@ -66,29 +72,34 @@ public class AnalyticsCollector /** * Creates an analytics collector for the specified player. * - * @param player The {@link Player} for which data will be collected. + * @param player The {@link Player} for which data will be collected. Can be null, if the player + * is set by calling {@link AnalyticsCollector#setPlayer(Player)} before using the analytics + * collector. * @param clock A {@link Clock} used to generate timestamps. * @return An analytics collector. */ - public AnalyticsCollector createAnalyticsCollector(Player player, Clock clock) { + public AnalyticsCollector createAnalyticsCollector(@Nullable Player player, Clock clock) { return new AnalyticsCollector(player, clock); } } private final CopyOnWriteArraySet listeners; - private final Player player; private final Clock clock; private final Window window; private final MediaPeriodQueueTracker mediaPeriodQueueTracker; + private @MonotonicNonNull Player player; + /** * Creates an analytics collector for the specified player. * - * @param player The {@link Player} for which data will be collected. + * @param player The {@link Player} for which data will be collected. Can be null, if the player + * is set by calling {@link AnalyticsCollector#setPlayer(Player)} before using the analytics + * collector. * @param clock A {@link Clock} used to generate timestamps. */ - protected AnalyticsCollector(Player player, Clock clock) { - this.player = Assertions.checkNotNull(player); + protected AnalyticsCollector(@Nullable Player player, Clock clock) { + this.player = player; this.clock = Assertions.checkNotNull(clock); listeners = new CopyOnWriteArraySet<>(); mediaPeriodQueueTracker = new MediaPeriodQueueTracker(); @@ -113,6 +124,17 @@ public class AnalyticsCollector listeners.remove(listener); } + /** + * Sets the player for which data will be collected. Must only be called if no player has been set + * yet. + * + * @param player The {@link Player} for which data will be collected. + */ + public void setPlayer(Player player) { + Assertions.checkState(this.player == null); + this.player = Assertions.checkNotNull(player); + } + // External events. /** @@ -129,31 +151,6 @@ public class AnalyticsCollector } } - /** - * Notify analytics collector that the viewport size changed. - * - * @param width The new width of the viewport in device-independent pixels (dp). - * @param height The new height of the viewport in device-independent pixels (dp). - */ - public final void notifyViewportSizeChanged(int width, int height) { - EventTime eventTime = generatePlayingMediaPeriodEventTime(); - for (AnalyticsListener listener : listeners) { - listener.onViewportSizeChange(eventTime, width, height); - } - } - - /** - * Notify analytics collector that the network type or connectivity changed. - * - * @param networkInfo The new network info, or null if no network connection exists. - */ - public final void notifyNetworkTypeChanged(@Nullable NetworkInfo networkInfo) { - EventTime eventTime = generatePlayingMediaPeriodEventTime(); - for (AnalyticsListener listener : listeners) { - listener.onNetworkTypeChanged(eventTime, networkInfo); - } - } - /** * Resets the analytics collector for a new media source. Should be called before the player is * prepared with a new media source. @@ -188,14 +185,6 @@ public class AnalyticsCollector } } - @Override - public final void onAudioSessionId(int audioSessionId) { - EventTime eventTime = generateReadingMediaPeriodEventTime(); - for (AnalyticsListener listener : listeners) { - listener.onAudioSessionId(eventTime, audioSessionId); - } - } - @Override public final void onAudioDecoderInitialized( String decoderName, long initializedTimestampMs, long initializationDurationMs) { @@ -233,6 +222,32 @@ public class AnalyticsCollector } } + // AudioListener implementation. + + @Override + public final void onAudioSessionId(int audioSessionId) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onAudioSessionId(eventTime, audioSessionId); + } + } + + @Override + public void onAudioAttributesChanged(AudioAttributes audioAttributes) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onAudioAttributesChanged(eventTime, audioAttributes); + } + } + + @Override + public void onVolumeChanged(float audioVolume) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onVolumeChanged(eventTime, audioVolume); + } + } + // VideoRendererEventListener implementation. @Override @@ -271,12 +286,12 @@ public class AnalyticsCollector } @Override - public final void onVideoSizeChanged( - int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - EventTime eventTime = generateReadingMediaPeriodEventTime(); + public final void onVideoDisabled(DecoderCounters counters) { + // The renderers are disabled after we changed the playing media period on the playback thread + // but before this change is reported to the app thread. + EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime(); for (AnalyticsListener listener : listeners) { - listener.onVideoSizeChanged( - eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio); + listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters); } } @@ -288,16 +303,31 @@ public class AnalyticsCollector } } + // VideoListener implementation. + @Override - public final void onVideoDisabled(DecoderCounters counters) { - // The renderers are disabled after we changed the playing media period on the playback thread - // but before this change is reported to the app thread. - EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime(); + public final void onVideoSizeChanged( + int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); for (AnalyticsListener listener : listeners) { - listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters); + listener.onVideoSizeChanged( + eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio); } } + @Override + public void onSurfaceSizeChanged(int width, int height) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onSurfaceSizeChanged(eventTime, width, height); + } + } + + @Override + public final void onRenderedFirstFrame() { + // Do nothing. Already reported in VideoRendererEventListener.onRenderedFirstFrame. + } + // MediaSourceEventListener implementation. @Override @@ -420,6 +450,16 @@ public class AnalyticsCollector } } + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + + } + @Override public final void onLoadingChanged(boolean isLoading) { EventTime eventTime = generatePlayingMediaPeriodEventTime(); @@ -541,6 +581,7 @@ public class AnalyticsCollector /** Returns a new {@link EventTime} for the specified window index and media period id. */ protected EventTime generateEventTime(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) { + Assertions.checkNotNull(player); long realtimeMs = clock.elapsedRealtime(); Timeline timeline = player.getCurrentTimeline(); long eventPositionMs; @@ -565,8 +606,6 @@ public class AnalyticsCollector // This event is for content in a future window. Assume default start position. eventPositionMs = timeline.getWindow(windowIndex, window).getDefaultPositionMs(); } - // TODO(b/30792113): implement this properly (player.getTotalBufferedDuration()). - long bufferedDurationMs = player.getBufferedPosition() - player.getContentPosition(); return new EventTime( realtimeMs, timeline, @@ -574,12 +613,12 @@ public class AnalyticsCollector mediaPeriodId, eventPositionMs, player.getCurrentPosition(), - bufferedDurationMs); + player.getTotalBufferedDuration()); } private EventTime generateEventTime(@Nullable WindowAndMediaPeriodId mediaPeriod) { if (mediaPeriod == null) { - int windowIndex = player.getCurrentWindowIndex(); + int windowIndex = Assertions.checkNotNull(player).getCurrentWindowIndex(); MediaPeriodId mediaPeriodId = mediaPeriodQueueTracker.tryResolveWindowIndex(windowIndex); return generateEventTime(windowIndex, mediaPeriodId); } @@ -756,8 +795,7 @@ public class AnalyticsCollector if (newTimeline.isEmpty() || timeline.isEmpty()) { return mediaPeriod; } - Object uid = - timeline.getPeriod(mediaPeriod.mediaPeriodId.periodIndex, period, /* setIds= */ true).uid; + Object uid = timeline.getUidOfPeriod(mediaPeriod.mediaPeriodId.periodIndex); int newPeriodIndex = newTimeline.getIndexOfPeriod(uid); if (newPeriodIndex == C.INDEX_UNSET) { return mediaPeriod; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java similarity index 74% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java index 0bef90631..adc4b3cdb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/AnalyticsListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java @@ -13,27 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.analytics; +package com.google.android.exoplayer2.analytics; -import android.net.NetworkInfo; import android.support.annotation.Nullable; import android.view.Surface; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason; -import org.telegram.messenger.exoplayer2.Player.TimelineChangeReason; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.audio.AudioSink; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Player.DiscontinuityReason; +import com.google.android.exoplayer2.Player.TimelineChangeReason; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.audio.AudioAttributes; +import com.google.android.exoplayer2.audio.AudioSink; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; +import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import java.io.IOException; /** @@ -41,6 +41,8 @@ import java.io.IOException; * *

    All events are recorded with an {@link EventTime} specifying the elapsed real time and media * time at the time of the event. + * + *

    All methods have no-op default implementations to allow selective overrides. */ public interface AnalyticsListener { @@ -127,7 +129,8 @@ public interface AnalyticsListener { * @param playWhenReady Whether the playback will proceed when ready. * @param playbackState One of the {@link Player}.STATE constants. */ - void onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState); + default void onPlayerStateChanged( + EventTime eventTime, boolean playWhenReady, int playbackState) {} /** * Called when the timeline changed. @@ -135,7 +138,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param reason The reason for the timeline change. */ - void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason); + default void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason) {} /** * Called when a position discontinuity occurred. @@ -143,21 +146,21 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param reason The reason for the position discontinuity. */ - void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason); + default void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason) {} /** * Called when a seek operation started. * * @param eventTime The event time. */ - void onSeekStarted(EventTime eventTime); + default void onSeekStarted(EventTime eventTime) {} /** * Called when a seek operation was processed. * * @param eventTime The event time. */ - void onSeekProcessed(EventTime eventTime); + default void onSeekProcessed(EventTime eventTime) {} /** * Called when the playback parameters changed. @@ -165,7 +168,8 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param playbackParameters The new playback parameters. */ - void onPlaybackParametersChanged(EventTime eventTime, PlaybackParameters playbackParameters); + default void onPlaybackParametersChanged( + EventTime eventTime, PlaybackParameters playbackParameters) {} /** * Called when the repeat mode changed. @@ -173,7 +177,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param repeatMode The new repeat mode. */ - void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode); + default void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode) {} /** * Called when the shuffle mode changed. @@ -181,7 +185,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param shuffleModeEnabled Whether the shuffle mode is enabled. */ - void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled); + default void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled) {} /** * Called when the player starts or stops loading data from a source. @@ -189,7 +193,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param isLoading Whether the player is loading. */ - void onLoadingChanged(EventTime eventTime, boolean isLoading); + default void onLoadingChanged(EventTime eventTime, boolean isLoading) {} /** * Called when a fatal player error occurred. @@ -197,7 +201,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param error The error. */ - void onPlayerError(EventTime eventTime, ExoPlaybackException error); + default void onPlayerError(EventTime eventTime, ExoPlaybackException error) {} /** * Called when the available or selected tracks for the renderers changed. @@ -206,8 +210,8 @@ public interface AnalyticsListener { * @param trackGroups The available tracks. May be empty. * @param trackSelections The track selections for each renderer. May contain null elements. */ - void onTracksChanged( - EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections); + default void onTracksChanged( + EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {} /** * Called when a media source started loading data. @@ -216,7 +220,8 @@ public interface AnalyticsListener { * @param loadEventInfo The {@link LoadEventInfo} defining the load event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ - void onLoadStarted(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData); + default void onLoadStarted( + EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} /** * Called when a media source completed loading data. @@ -225,8 +230,8 @@ public interface AnalyticsListener { * @param loadEventInfo The {@link LoadEventInfo} defining the load event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ - void onLoadCompleted( - EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData); + default void onLoadCompleted( + EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} /** * Called when a media source canceled loading data. @@ -235,8 +240,8 @@ public interface AnalyticsListener { * @param loadEventInfo The {@link LoadEventInfo} defining the load event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ - void onLoadCanceled( - EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData); + default void onLoadCanceled( + EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} /** * Called when a media source loading error occurred. These errors are just for informational @@ -248,12 +253,12 @@ public interface AnalyticsListener { * @param error The load error. * @param wasCanceled Whether the load was canceled as a result of the error. */ - void onLoadError( + default void onLoadError( EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData, IOException error, - boolean wasCanceled); + boolean wasCanceled) {} /** * Called when the downstream format sent to the renderers changed. @@ -261,7 +266,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param mediaLoadData The {@link MediaLoadData} defining the newly selected media data. */ - void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData); + default void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {} /** * Called when data is removed from the back of a media buffer, typically so that it can be @@ -270,28 +275,28 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param mediaLoadData The {@link MediaLoadData} defining the media being discarded. */ - void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData); + default void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) {} /** * Called when a media source created a media period. * * @param eventTime The event time. */ - void onMediaPeriodCreated(EventTime eventTime); + default void onMediaPeriodCreated(EventTime eventTime) {} /** * Called when a media source released a media period. * * @param eventTime The event time. */ - void onMediaPeriodReleased(EventTime eventTime); + default void onMediaPeriodReleased(EventTime eventTime) {} /** * Called when the player started reading a media period. * * @param eventTime The event time. */ - void onReadingStarted(EventTime eventTime); + default void onReadingStarted(EventTime eventTime) {} /** * Called when the bandwidth estimate for the current data source has been updated. @@ -301,25 +306,19 @@ public interface AnalyticsListener { * @param totalBytesLoaded The total bytes loaded this update is based on. * @param bitrateEstimate The bandwidth estimate, in bits per second. */ - void onBandwidthEstimate( - EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate); + default void onBandwidthEstimate( + EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {} /** - * Called when the viewport size of the output surface changed. + * Called when the output surface size changed. * * @param eventTime The event time. - * @param width The width of the viewport in device-independent pixels (dp). - * @param height The height of the viewport in device-independent pixels (dp). + * @param width The surface width in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if the + * video is not rendered onto a surface. + * @param height The surface height in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if + * the video is not rendered onto a surface. */ - void onViewportSizeChange(EventTime eventTime, int width, int height); - - /** - * Called when the type of the network connection changed. - * - * @param eventTime The event time. - * @param networkInfo The network info for the current connection, or null if disconnected. - */ - void onNetworkTypeChanged(EventTime eventTime, @Nullable NetworkInfo networkInfo); + default void onSurfaceSizeChanged(EventTime eventTime, int width, int height) {} /** * Called when there is {@link Metadata} associated with the current playback time. @@ -327,7 +326,7 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param metadata The metadata. */ - void onMetadata(EventTime eventTime, Metadata metadata); + default void onMetadata(EventTime eventTime, Metadata metadata) {} /** * Called when an audio or video decoder has been enabled. @@ -337,7 +336,8 @@ public interface AnalyticsListener { * {@link C#TRACK_TYPE_VIDEO}. * @param decoderCounters The accumulated event counters associated with this decoder. */ - void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters decoderCounters); + default void onDecoderEnabled( + EventTime eventTime, int trackType, DecoderCounters decoderCounters) {} /** * Called when an audio or video decoder has been initialized. @@ -348,8 +348,8 @@ public interface AnalyticsListener { * @param decoderName The decoder that was created. * @param initializationDurationMs Time taken to initialize the decoder, in milliseconds. */ - void onDecoderInitialized( - EventTime eventTime, int trackType, String decoderName, long initializationDurationMs); + default void onDecoderInitialized( + EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) {} /** * Called when an audio or video decoder input format changed. @@ -359,7 +359,7 @@ public interface AnalyticsListener { * C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}. * @param format The new input format for the decoder. */ - void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format); + default void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format) {} /** * Called when an audio or video decoder has been disabled. @@ -369,7 +369,8 @@ public interface AnalyticsListener { * {@link C#TRACK_TYPE_VIDEO}. * @param decoderCounters The accumulated event counters associated with this decoder. */ - void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters decoderCounters); + default void onDecoderDisabled( + EventTime eventTime, int trackType, DecoderCounters decoderCounters) {} /** * Called when the audio session id is set. @@ -377,7 +378,23 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param audioSessionId The audio session id. */ - void onAudioSessionId(EventTime eventTime, int audioSessionId); + default void onAudioSessionId(EventTime eventTime, int audioSessionId) {} + + /** + * Called when the audio attributes change. + * + * @param eventTime The event time. + * @param audioAttributes The audio attributes. + */ + default void onAudioAttributesChanged(EventTime eventTime, AudioAttributes audioAttributes) {} + + /** + * Called when the volume changes. + * + * @param eventTime The event time. + * @param volume The new volume, with 0 being silence and 1 being unity gain. + */ + default void onVolumeChanged(EventTime eventTime, float volume) {} /** * Called when an audio underrun occurred. @@ -389,8 +406,8 @@ public interface AnalyticsListener { * as the buffered media can have a variable bitrate so the duration may be unknown. * @param elapsedSinceLastFeedMs The time since the {@link AudioSink} was last fed data. */ - void onAudioUnderrun( - EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs); + default void onAudioUnderrun( + EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {} /** * Called after video frames have been dropped. @@ -401,7 +418,7 @@ public interface AnalyticsListener { * is timed from when the renderer was started or from when dropped frames were last reported * (whichever was more recent), and not from when the first of the reported drops occurred. */ - void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs); + default void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {} /** * Called before a frame is rendered for the first time since setting the surface, and each time @@ -416,12 +433,12 @@ public interface AnalyticsListener { * since the renderer will apply all necessary rotations internally. * @param pixelWidthHeightRatio The width to height ratio of each pixel. */ - void onVideoSizeChanged( + default void onVideoSizeChanged( EventTime eventTime, int width, int height, int unappliedRotationDegrees, - float pixelWidthHeightRatio); + float pixelWidthHeightRatio) {} /** * Called when a frame is rendered for the first time since setting the surface, and when a frame @@ -431,14 +448,14 @@ public interface AnalyticsListener { * @param surface The {@link Surface} to which a first frame has been rendered, or {@code null} if * the renderer renders to something that isn't a {@link Surface}. */ - void onRenderedFirstFrame(EventTime eventTime, Surface surface); + default void onRenderedFirstFrame(EventTime eventTime, Surface surface) {} /** * Called each time drm keys are loaded. * * @param eventTime The event time. */ - void onDrmKeysLoaded(EventTime eventTime); + default void onDrmKeysLoaded(EventTime eventTime) {} /** * Called when a drm error occurs. These errors are just for informational purposes and the player @@ -447,19 +464,19 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param error The error. */ - void onDrmSessionManagerError(EventTime eventTime, Exception error); + default void onDrmSessionManagerError(EventTime eventTime, Exception error) {} /** * Called each time offline drm keys are restored. * * @param eventTime The event time. */ - void onDrmKeysRestored(EventTime eventTime); + default void onDrmKeysRestored(EventTime eventTime) {} /** * Called each time offline drm keys are removed. * * @param eventTime The event time. */ - void onDrmKeysRemoved(EventTime eventTime); + default void onDrmKeysRemoved(EventTime eventTime) {} } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/DefaultAnalyticsListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/DefaultAnalyticsListener.java new file mode 100755 index 000000000..d487a8aa9 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/analytics/DefaultAnalyticsListener.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.analytics; + +/** + * @deprecated Use {@link AnalyticsListener} directly for selective overrides as all methods are + * implemented as no-op default methods. + */ +@Deprecated +public abstract class DefaultAnalyticsListener implements AnalyticsListener {} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Ac3Util.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Ac3Util.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java index 0572d8534..94fe759a9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Ac3Util.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; @@ -137,17 +137,17 @@ public final class Ac3Util { 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393}; /** - * Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to - * ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified. + * Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to ETSI TS + * 102 366 Annex F. The reading position of {@code data} will be modified. * * @param data The AC3SpecificBox to parse. - * @param trackId The track identifier to set on the format, or null. + * @param trackId The track identifier to set on the format. * @param language The language to set on the format. * @param drmInitData {@link DrmInitData} to be included in the format. * @return The AC-3 format parsed from data in the header. */ - public static Format parseAc3AnnexFFormat(ParsableByteArray data, String trackId, - String language, DrmInitData drmInitData) { + public static Format parseAc3AnnexFFormat( + ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) { int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod]; int nextByte = data.readUnsignedByte(); @@ -155,22 +155,32 @@ public final class Ac3Util { if ((nextByte & 0x04) != 0) { // lfeon channelCount++; } - return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, null, Format.NO_VALUE, - Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language); + return Format.createAudioSampleFormat( + trackId, + MimeTypes.AUDIO_AC3, + /* codecs= */ null, + Format.NO_VALUE, + Format.NO_VALUE, + channelCount, + sampleRate, + /* initializationData= */ null, + drmInitData, + /* selectionFlags= */ 0, + language); } /** - * Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to - * ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified. + * Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to ETSI TS + * 102 366 Annex F. The reading position of {@code data} will be modified. * * @param data The EC3SpecificBox to parse. - * @param trackId The track identifier to set on the format, or null. + * @param trackId The track identifier to set on the format. * @param language The language to set on the format. * @param drmInitData {@link DrmInitData} to be included in the format. * @return The E-AC-3 format parsed from data in the header. */ - public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackId, - String language, DrmInitData drmInitData) { + public static Format parseEAc3AnnexFFormat( + ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) { data.skipBytes(2); // data_rate, num_ind_sub // Read the first independent substream. @@ -200,8 +210,18 @@ public final class Ac3Util { mimeType = MimeTypes.AUDIO_E_AC3_JOC; } } - return Format.createAudioSampleFormat(trackId, mimeType, null, Format.NO_VALUE, - Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language); + return Format.createAudioSampleFormat( + trackId, + mimeType, + /* codecs= */ null, + Format.NO_VALUE, + Format.NO_VALUE, + channelCount, + sampleRate, + /* initializationData= */ null, + drmInitData, + /* selectionFlags= */ 0, + language); } /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioAttributes.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioAttributes.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java index ad7792e0d..f726805c4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioAttributes.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.annotation.TargetApi; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** * Attributes for audio playback, which configure the underlying platform * {@link android.media.AudioTrack}. *

    * To set the audio attributes, create an instance using the {@link Builder} and either pass it to - * {@link org.telegram.messenger.exoplayer2.SimpleExoPlayer#setAudioAttributes(AudioAttributes)} or + * {@link com.google.android.exoplayer2.SimpleExoPlayer#setAudioAttributes(AudioAttributes)} or * send a message of type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to the audio renderers. *

    * This class is based on {@link android.media.AudioAttributes}, but can be used on all supported @@ -39,12 +39,9 @@ public final class AudioAttributes { */ public static final class Builder { - @C.AudioContentType - private int contentType; - @C.AudioFlags - private int flags; - @C.AudioUsage - private int usage; + private @C.AudioContentType int contentType; + private @C.AudioFlags int flags; + private @C.AudioUsage int usage; /** * Creates a new builder for {@link AudioAttributes}. @@ -91,14 +88,11 @@ public final class AudioAttributes { } - @C.AudioContentType - public final int contentType; - @C.AudioFlags - public final int flags; - @C.AudioUsage - public final int usage; + public final @C.AudioContentType int contentType; + public final @C.AudioFlags int flags; + public final @C.AudioUsage int usage; - private android.media.AudioAttributes audioAttributesV21; + private @Nullable android.media.AudioAttributes audioAttributesV21; private AudioAttributes(@C.AudioContentType int contentType, @C.AudioFlags int flags, @C.AudioUsage int usage) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilities.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilities.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java index 51215bce3..8d18adf56 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilities.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -50,7 +50,7 @@ public final class AudioCapabilities { } @SuppressLint("InlinedApi") - /* package */ static AudioCapabilities getCapabilities(Intent intent) { + /* package */ static AudioCapabilities getCapabilities(@Nullable Intent intent) { if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { return DEFAULT_AUDIO_CAPABILITIES; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilitiesReceiver.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilitiesReceiver.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java index 5d2495dcd..1eb0ec466 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioCapabilitiesReceiver.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilitiesReceiver.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; /** * Receives broadcast events indicating changes to the device's audio capabilities, notifying a @@ -45,9 +46,9 @@ public final class AudioCapabilitiesReceiver { private final Context context; private final Listener listener; - private final BroadcastReceiver receiver; + private final @Nullable BroadcastReceiver receiver; - /* package */ AudioCapabilities audioCapabilities; + /* package */ @Nullable AudioCapabilities audioCapabilities; /** * @param context A context for registering the receiver. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioDecoderException.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioDecoderException.java index c975b2b82..ac4f632d6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioDecoderException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; /** Thrown when an audio decoder error occurs. */ public class AudioDecoderException extends Exception { diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java new file mode 100755 index 000000000..8ce365b28 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.audio; + +/** A listener for changes in audio configuration. */ +public interface AudioListener { + + /** + * Called when the audio session is set. + * + * @param audioSessionId The audio session id. + */ + default void onAudioSessionId(int audioSessionId) {} + + /** + * Called when the audio attributes change. + * + * @param audioAttributes The audio attributes. + */ + default void onAudioAttributesChanged(AudioAttributes audioAttributes) {} + + /** + * Called when the volume changes. + * + * @param volume The new volume, with 0 being silence and 1 being unity gain. + */ + default void onVolumeChanged(float volume) {} +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java index d3ea233d8..f82be31f7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioRendererEventListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioRendererEventListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java index d75b86bb4..7a4958a61 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioRendererEventListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.os.Handler; import android.os.SystemClock; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.Renderer; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.util.Assertions; /** * Listener of audio {@link Renderer} events. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java index 12bdb6a79..07584d575 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.media.AudioTrack; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.PlaybackParameters; import java.nio.ByteBuffer; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTimestampPoller.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTimestampPoller.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTimestampPoller.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTimestampPoller.java index db29c4ff7..47120e737 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTimestampPoller.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTimestampPoller.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.annotation.TargetApi; import android.media.AudioTimestamp; import android.media.AudioTrack; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTrackPositionTracker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTrackPositionTracker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java index 718d4a17e..009500129 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/AudioTrackPositionTracker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java @@ -13,15 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.media.AudioTimestamp; import android.media.AudioTrack; import android.os.SystemClock; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; @@ -128,10 +131,10 @@ import java.lang.reflect.Method; private final Listener listener; private final long[] playheadOffsets; - private AudioTrack audioTrack; + private @Nullable AudioTrack audioTrack; private int outputPcmFrameSize; private int bufferSize; - private AudioTimestampPoller audioTimestampPoller; + private @Nullable AudioTimestampPoller audioTimestampPoller; private int outputSampleRate; private boolean needsPassthroughWorkarounds; private long bufferSizeUs; @@ -139,7 +142,7 @@ import java.lang.reflect.Method; private long smoothedPlayheadOffsetUs; private long lastPlayheadSampleTimeUs; - private Method getLatencyMethod; + private @Nullable Method getLatencyMethod; private long latencyUs; private boolean hasData; @@ -193,7 +196,7 @@ import java.lang.reflect.Method; audioTimestampPoller = new AudioTimestampPoller(audioTrack); outputSampleRate = audioTrack.getSampleRate(); needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding); - isOutputPcm = Util.isEncodingPcm(outputEncoding); + isOutputPcm = Util.isEncodingLinearPcm(outputEncoding); bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET; lastRawPlaybackHeadPosition = 0; rawPlaybackHeadWrapCount = 0; @@ -205,13 +208,14 @@ import java.lang.reflect.Method; } public long getCurrentPositionUs(boolean sourceEnded) { - if (audioTrack.getPlayState() == PLAYSTATE_PLAYING) { + if (Assertions.checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) { maybeSampleSyncParams(); } // If the device supports it, use the playback timestamp from AudioTrack.getTimestamp. // Otherwise, derive a smoothed position by sampling the track's frame position. long systemTimeUs = System.nanoTime() / 1000; + AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller); if (audioTimestampPoller.hasTimestamp()) { // Calculate the speed-adjusted position using the timestamp (which may be in the future). long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); @@ -241,12 +245,12 @@ import java.lang.reflect.Method; /** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */ public void start() { - audioTimestampPoller.reset(); + Assertions.checkNotNull(audioTimestampPoller).reset(); } /** Returns whether the audio track is in the playing state. */ public boolean isPlaying() { - return audioTrack.getPlayState() == PLAYSTATE_PLAYING; + return Assertions.checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING; } /** @@ -257,7 +261,7 @@ import java.lang.reflect.Method; * @return Whether the caller can write data to the track. */ public boolean mayHandleBuffer(long writtenFrames) { - @PlayState int playState = audioTrack.getPlayState(); + @PlayState int playState = Assertions.checkNotNull(audioTrack).getPlayState(); if (needsPassthroughWorkarounds) { // An AC-3 audio track continues to play data written while it is paused. Stop writing so its // buffer empties. See [Internal: b/18899620]. @@ -339,7 +343,7 @@ import java.lang.reflect.Method; if (stopTimestampUs == C.TIME_UNSET) { // The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't // supply an advancing position. - audioTimestampPoller.reset(); + Assertions.checkNotNull(audioTimestampPoller).reset(); return true; } // We've handled the end of the stream already, so there's no need to pause the track. @@ -388,6 +392,7 @@ import java.lang.reflect.Method; } private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) { + AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller); if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) { return; } @@ -423,7 +428,9 @@ import java.lang.reflect.Method; // Compute the audio track latency, excluding the latency due to the buffer (leaving // latency due to the mixer and audio hardware driver). latencyUs = - (Integer) getLatencyMethod.invoke(audioTrack, (Object[]) null) * 1000L - bufferSizeUs; + castNonNull((Integer) getLatencyMethod.invoke(Assertions.checkNotNull(audioTrack))) + * 1000L + - bufferSizeUs; // Sanity check that the latency is non-negative. latencyUs = Math.max(latencyUs, 0); // Sanity check that the latency isn't too large. @@ -457,7 +464,7 @@ import java.lang.reflect.Method; */ private boolean forceHasPendingData() { return needsPassthroughWorkarounds - && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED + && Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED && getPlaybackHeadPosition() == 0; } @@ -483,6 +490,7 @@ import java.lang.reflect.Method; * @return The playback head position, in frames. */ private long getPlaybackHeadPosition() { + AudioTrack audioTrack = Assertions.checkNotNull(this.audioTrack); if (stopTimestampUs != C.TIME_UNSET) { // Simulate the playback head position up to the total number of frames submitted. long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ChannelMappingAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ChannelMappingAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java index 2a8cfab28..e53eb08c8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ChannelMappingAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.C.Encoding; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.C.Encoding; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Assertions; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DefaultAudioSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DefaultAudioSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index 52d76e5a1..e449e5566 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DefaultAudioSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -25,10 +25,10 @@ import android.os.SystemClock; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; @@ -371,7 +371,7 @@ public final class DefaultAudioSink implements AudioSink { @Override public boolean isEncodingSupported(@C.Encoding int encoding) { - if (Util.isEncodingPcm(encoding)) { + if (Util.isEncodingLinearPcm(encoding)) { // AudioTrack supports 16-bit integer PCM output in all platform API versions, and float // output from platform API version 21 only. Other integer PCM encodings are resampled by this // sink to 16-bit PCM. @@ -405,7 +405,7 @@ public final class DefaultAudioSink implements AudioSink { this.inputSampleRate = inputSampleRate; int channelCount = inputChannelCount; int sampleRate = inputSampleRate; - isInputPcm = Util.isEncodingPcm(inputEncoding); + isInputPcm = Util.isEncodingLinearPcm(inputEncoding); shouldConvertHighResIntPcmToFloat = enableConvertHighResIntPcmToFloat && isEncodingSupported(C.ENCODING_PCM_32BIT) diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DtsUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DtsUtil.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DtsUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DtsUtil.java index 1791bb14b..f65dc3fc4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/DtsUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/DtsUtil.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableBitArray; import java.nio.ByteBuffer; import java.util.Arrays; @@ -74,13 +74,13 @@ public final class DtsUtil { * subsections 5.3/5.4. * * @param frame The DTS frame to parse. - * @param trackId The track identifier to set on the format, or null. + * @param trackId The track identifier to set on the format. * @param language The language to set on the format. * @param drmInitData {@link DrmInitData} to be included in the format. * @return The DTS format parsed from data in the header. */ - public static Format parseDtsFormat(byte[] frame, String trackId, String language, - DrmInitData drmInitData) { + public static Format parseDtsFormat( + byte[] frame, String trackId, String language, DrmInitData drmInitData) { ParsableBitArray frameBits = getNormalizedFrameHeader(frame); frameBits.skipBits(32 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE int amode = frameBits.readBits(6); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/FloatResamplingAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/FloatResamplingAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java index 637bdd2fd..e3c91cd34 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/FloatResamplingAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/MediaCodecAudioRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/MediaCodecAudioRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 28efad093..689cfc41c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -25,26 +25,28 @@ import android.media.MediaFormat; import android.media.audiofx.Virtualizer; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.PlayerMessage.Target; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecInfo; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecRenderer; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; -import org.telegram.messenger.exoplayer2.mediacodec.MediaFormatUtil; -import org.telegram.messenger.exoplayer2.util.MediaClock; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.PlayerMessage.Target; +import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; +import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer; +import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; +import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import com.google.android.exoplayer2.mediacodec.MediaFormatUtil; +import com.google.android.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; /** * Decodes and renders audio using {@link MediaCodec} and an {@link AudioSink}. @@ -56,7 +58,7 @@ import java.nio.ByteBuffer; *

  • Message with type {@link C#MSG_SET_VOLUME} to set the volume. The message payload should be * a {@link Float} with 0 being silence and 1 being unity gain. *
  • Message with type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to set the audio attributes. The - * message payload should be an {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes} + * message payload should be an {@link com.google.android.exoplayer2.audio.AudioAttributes} * instance that will configure the underlying audio track. *
*/ @@ -229,7 +231,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media @Nullable Handler eventHandler, @Nullable AudioRendererEventListener eventListener, AudioSink audioSink) { - super(C.TRACK_TYPE_AUDIO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys); + super( + C.TRACK_TYPE_AUDIO, + mediaCodecSelector, + drmSessionManager, + playClearSamplesWithoutKeys, + /* assumedMinimumCodecOperatingRate= */ 44100); this.context = context.getApplicationContext(); this.audioSink = audioSink; eventDispatcher = new EventDispatcher(eventHandler, eventListener); @@ -262,15 +269,21 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption; } } - MediaCodecInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, - requiresSecureDecryption); - if (decoderInfo == null) { - return requiresSecureDecryption && mediaCodecSelector.getDecoderInfo(mimeType, false) != null - ? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE; + List decoderInfos = + mediaCodecSelector.getDecoderInfos(format, requiresSecureDecryption); + if (decoderInfos.isEmpty()) { + return requiresSecureDecryption + && !mediaCodecSelector + .getDecoderInfos(format, /* requiresSecureDecoder= */ false) + .isEmpty() + ? FORMAT_UNSUPPORTED_DRM + : FORMAT_UNSUPPORTED_SUBTYPE; } if (!supportsFormatDrm) { return FORMAT_UNSUPPORTED_DRM; } + // Check capabilities for the first decoder in the list, which takes priority. + MediaCodecInfo decoderInfo = decoderInfos.get(0); // Note: We assume support for unknown sampleRate and channelCount. boolean decoderCapable = Util.SDK_INT < 21 || ((format.sampleRate == Format.NO_VALUE @@ -282,15 +295,16 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } @Override - protected MediaCodecInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, - Format format, boolean requiresSecureDecoder) throws DecoderQueryException { + protected List getDecoderInfos( + MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) + throws DecoderQueryException { if (allowPassthrough(format.sampleMimeType)) { MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo(); if (passthroughDecoderInfo != null) { - return passthroughDecoderInfo; + return Collections.singletonList(passthroughDecoderInfo); } } - return super.getDecoderInfo(mediaCodecSelector, format, requiresSecureDecoder); + return super.getDecoderInfos(mediaCodecSelector, format, requiresSecureDecoder); } /** @@ -307,13 +321,18 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } @Override - protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, - MediaCrypto crypto) { + protected void configureCodec( + MediaCodecInfo codecInfo, + MediaCodec codec, + Format format, + MediaCrypto crypto, + float codecOperatingRate) { codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats()); codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name); passthroughEnabled = codecInfo.passthrough; String codecMimeType = codecInfo.mimeType == null ? MimeTypes.AUDIO_RAW : codecInfo.mimeType; - MediaFormat mediaFormat = getMediaFormat(format, codecMimeType, codecMaxInputSize); + MediaFormat mediaFormat = + getMediaFormat(format, codecMimeType, codecMaxInputSize, codecOperatingRate); codec.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0); if (passthroughEnabled) { // Store the input MIME type if we're using the passthrough codec. @@ -341,6 +360,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media return this; } + @Override + protected float getCodecOperatingRate( + float operatingRate, Format format, Format[] streamFormats) { + return format.sampleRate == Format.NO_VALUE + ? CODEC_OPERATING_RATE_UNSET + : (format.sampleRate * operatingRate); + } + @Override protected void onCodecInitialized(String name, long initializedTimestampMs, long initializationDurationMs) { @@ -624,10 +651,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media * @param format The format of the media. * @param codecMimeType The MIME type handled by the codec. * @param codecMaxInputSize The maximum input size supported by the codec. + * @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if + * no codec operating rate should be set. * @return The framework media format. */ @SuppressLint("InlinedApi") - protected MediaFormat getMediaFormat(Format format, String codecMimeType, int codecMaxInputSize) { + protected MediaFormat getMediaFormat( + Format format, String codecMimeType, int codecMaxInputSize, float codecOperatingRate) { MediaFormat mediaFormat = new MediaFormat(); // Set format parameters that should always be set. mediaFormat.setString(MediaFormat.KEY_MIME, codecMimeType); @@ -639,6 +669,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media // Set codec configuration values. if (Util.SDK_INT >= 23) { mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */); + if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) { + mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate); + } } return mediaFormat; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ResamplingAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ResamplingAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java index 478091a66..eac0bffd6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/ResamplingAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SilenceSkippingAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SilenceSkippingAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java index 144a06ce1..a289ced12 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SilenceSkippingAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SimpleDecoderAudioRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index a745f33b2..90dff0575 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -13,35 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.media.audiofx.Virtualizer; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.BaseRenderer; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.PlayerMessage.Target; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; -import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer; -import org.telegram.messenger.exoplayer2.drm.DrmSession; -import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MediaClock; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.TraceUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.BaseRenderer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.PlayerMessage.Target; +import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.decoder.SimpleDecoder; +import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; +import com.google.android.exoplayer2.drm.DrmSession; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.TraceUtil; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -55,7 +56,7 @@ import java.lang.annotation.RetentionPolicy; *
  • Message with type {@link C#MSG_SET_VOLUME} to set the volume. The message payload should be * a {@link Float} with 0 being silence and 1 being unity gain. *
  • Message with type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to set the audio attributes. The - * message payload should be an {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes} + * message payload should be an {@link com.google.android.exoplayer2.audio.AudioAttributes} * instance that will configure the underlying audio track. * */ @@ -121,7 +122,9 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements * @param eventListener A listener of events. May be null if delivery of events is not required. * @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. */ - public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, + public SimpleDecoderAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, AudioProcessor... audioProcessors) { this( eventHandler, @@ -139,8 +142,10 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements * @param audioCapabilities The audio capabilities for playback on this device. May be null if the * default capabilities (no encoded audio passthrough support) should be assumed. */ - public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, - AudioCapabilities audioCapabilities) { + public SimpleDecoderAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, + @Nullable AudioCapabilities audioCapabilities) { this( eventHandler, eventListener, @@ -164,9 +169,13 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements * has obtained the keys necessary to decrypt encrypted regions of the media. * @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. */ - public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, - AudioCapabilities audioCapabilities, DrmSessionManager drmSessionManager, - boolean playClearSamplesWithoutKeys, AudioProcessor... audioProcessors) { + public SimpleDecoderAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, + @Nullable AudioCapabilities audioCapabilities, + @Nullable DrmSessionManager drmSessionManager, + boolean playClearSamplesWithoutKeys, + AudioProcessor... audioProcessors) { this(eventHandler, eventListener, drmSessionManager, playClearSamplesWithoutKeys, new DefaultAudioSink(audioCapabilities, audioProcessors)); } @@ -184,8 +193,11 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements * has obtained the keys necessary to decrypt encrypted regions of the media. * @param audioSink The sink to which audio will be output. */ - public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, - DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, + public SimpleDecoderAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, + @Nullable DrmSessionManager drmSessionManager, + boolean playClearSamplesWithoutKeys, AudioSink audioSink) { super(C.TRACK_TYPE_AUDIO); this.drmSessionManager = drmSessionManager; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Sonic.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Sonic.java similarity index 55% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Sonic.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Sonic.java index df4255e77..0bf6baa4d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/Sonic.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/Sonic.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.nio.ShortBuffer; import java.util.Arrays; @@ -31,60 +31,6 @@ import java.util.Arrays; private static final int MAXIMUM_PITCH = 400; private static final int AMDF_FREQUENCY = 4000; - private static final int SINC_FILTER_POINTS = 12; - private static final int SINC_TABLE_SIZE = 601; - - private static final short sincTable[] = { - 0, 0, 0, 0, 0, 0, 0, -1, -1, -2, -2, -3, -4, -6, -7, -9, -10, -12, -14, - -17, -19, -21, -24, -26, -29, -32, -34, -37, -40, -42, -44, -47, -48, -50, - -51, -52, -53, -53, -53, -52, -50, -48, -46, -43, -39, -34, -29, -22, -16, - -8, 0, 9, 19, 29, 41, 53, 65, 79, 92, 107, 121, 137, 152, 168, 184, 200, - 215, 231, 247, 262, 276, 291, 304, 317, 328, 339, 348, 357, 363, 369, 372, - 374, 375, 373, 369, 363, 355, 345, 332, 318, 300, 281, 259, 234, 208, 178, - 147, 113, 77, 39, 0, -41, -85, -130, -177, -225, -274, -324, -375, -426, - -478, -530, -581, -632, -682, -731, -779, -825, -870, -912, -951, -989, - -1023, -1053, -1080, -1104, -1123, -1138, -1149, -1154, -1155, -1151, - -1141, -1125, -1105, -1078, -1046, -1007, -963, -913, -857, -796, -728, - -655, -576, -492, -403, -309, -210, -107, 0, 111, 225, 342, 462, 584, 708, - 833, 958, 1084, 1209, 1333, 1455, 1575, 1693, 1807, 1916, 2022, 2122, 2216, - 2304, 2384, 2457, 2522, 2579, 2625, 2663, 2689, 2706, 2711, 2705, 2687, - 2657, 2614, 2559, 2491, 2411, 2317, 2211, 2092, 1960, 1815, 1658, 1489, - 1308, 1115, 912, 698, 474, 241, 0, -249, -506, -769, -1037, -1310, -1586, - -1864, -2144, -2424, -2703, -2980, -3254, -3523, -3787, -4043, -4291, - -4529, -4757, -4972, -5174, -5360, -5531, -5685, -5819, -5935, -6029, - -6101, -6150, -6175, -6175, -6149, -6096, -6015, -5905, -5767, -5599, - -5401, -5172, -4912, -4621, -4298, -3944, -3558, -3141, -2693, -2214, - -1705, -1166, -597, 0, 625, 1277, 1955, 2658, 3386, 4135, 4906, 5697, 6506, - 7332, 8173, 9027, 9893, 10769, 11654, 12544, 13439, 14335, 15232, 16128, - 17019, 17904, 18782, 19649, 20504, 21345, 22170, 22977, 23763, 24527, - 25268, 25982, 26669, 27327, 27953, 28547, 29107, 29632, 30119, 30569, - 30979, 31349, 31678, 31964, 32208, 32408, 32565, 32677, 32744, 32767, - 32744, 32677, 32565, 32408, 32208, 31964, 31678, 31349, 30979, 30569, - 30119, 29632, 29107, 28547, 27953, 27327, 26669, 25982, 25268, 24527, - 23763, 22977, 22170, 21345, 20504, 19649, 18782, 17904, 17019, 16128, - 15232, 14335, 13439, 12544, 11654, 10769, 9893, 9027, 8173, 7332, 6506, - 5697, 4906, 4135, 3386, 2658, 1955, 1277, 625, 0, -597, -1166, -1705, - -2214, -2693, -3141, -3558, -3944, -4298, -4621, -4912, -5172, -5401, - -5599, -5767, -5905, -6015, -6096, -6149, -6175, -6175, -6150, -6101, - -6029, -5935, -5819, -5685, -5531, -5360, -5174, -4972, -4757, -4529, - -4291, -4043, -3787, -3523, -3254, -2980, -2703, -2424, -2144, -1864, - -1586, -1310, -1037, -769, -506, -249, 0, 241, 474, 698, 912, 1115, 1308, - 1489, 1658, 1815, 1960, 2092, 2211, 2317, 2411, 2491, 2559, 2614, 2657, - 2687, 2705, 2711, 2706, 2689, 2663, 2625, 2579, 2522, 2457, 2384, 2304, - 2216, 2122, 2022, 1916, 1807, 1693, 1575, 1455, 1333, 1209, 1084, 958, 833, - 708, 584, 462, 342, 225, 111, 0, -107, -210, -309, -403, -492, -576, -655, - -728, -796, -857, -913, -963, -1007, -1046, -1078, -1105, -1125, -1141, - -1151, -1155, -1154, -1149, -1138, -1123, -1104, -1080, -1053, -1023, -989, - -951, -912, -870, -825, -779, -731, -682, -632, -581, -530, -478, -426, - -375, -324, -274, -225, -177, -130, -85, -41, 0, 39, 77, 113, 147, 178, - 208, 234, 259, 281, 300, 318, 332, 345, 355, 363, 369, 373, 375, 374, 372, - 369, 363, 357, 348, 339, 328, 317, 304, 291, 276, 262, 247, 231, 215, 200, - 184, 168, 152, 137, 121, 107, 92, 79, 65, 53, 41, 29, 19, 9, 0, -8, -16, - -22, -29, -34, -39, -43, -46, -48, -50, -52, -53, -53, -53, -52, -51, -50, - -48, -47, -44, -42, -40, -37, -34, -32, -29, -26, -24, -21, -19, -17, -14, - -12, -10, -9, -7, -6, -4, -3, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0 - }; - private final int inputSampleRateHz; private final int channelCount; private final float speed; @@ -264,14 +210,14 @@ import java.util.Arrays; return frameCount; } - private void downSampleInput(short samples[], int position, int skip) { - int numSamples = maxRequiredFrameCount / skip; + private void downSampleInput(short[] samples, int position, int skip) { + // If skip is greater than one, average skip samples together and write them to the down-sample + // buffer. If channelCount is greater than one, mix the channels together as we down sample. + int frameCount = maxRequiredFrameCount / skip; int samplesPerValue = channelCount * skip; - int value; - position *= channelCount; - for (int i = 0; i < numSamples; i++) { - value = 0; + for (int i = 0; i < frameCount; i++) { + int value = 0; for (int j = 0; j < samplesPerValue; j++) { value += samples[position + i * samplesPerValue + j]; } @@ -280,35 +226,35 @@ import java.util.Arrays; } } - private int findPitchPeriodInRange( - short samples[], - int position, - int minPeriod, - int maxPeriod) - { - int bestPeriod = 0, worstPeriod = 255; - int minDiff = 1, maxDiff = 0; - + private int findPitchPeriodInRange(short[] samples, int position, int minPeriod, int maxPeriod) { + // Find the best frequency match in the range, and given a sample skip multiple. For now, just + // find the pitch of the first channel. + int bestPeriod = 0; + int worstPeriod = 255; + int minDiff = 1; + int maxDiff = 0; position *= channelCount; - for(int period = minPeriod; period <= maxPeriod; period++) { + for (int period = minPeriod; period <= maxPeriod; period++) { int diff = 0; - for(int i = 0; i < period; i++) { + for (int i = 0; i < period; i++) { short sVal = samples[position + i]; short pVal = samples[position + period + i]; - diff += sVal >= pVal? sVal - pVal : pVal - sVal; + diff += Math.abs(sVal - pVal); } - if(diff*bestPeriod < minDiff*period) { + // Note that the highest number of samples we add into diff will be less than 256, since we + // skip samples. Thus, diff is a 24 bit number, and we can safely multiply by numSamples + // without overflow. + if (diff * bestPeriod < minDiff * period) { minDiff = diff; bestPeriod = period; } - if(diff*worstPeriod > maxDiff*period) { + if (diff * worstPeriod > maxDiff * period) { maxDiff = diff; worstPeriod = period; } } - this.minDiff = minDiff/bestPeriod; - this.maxDiff = maxDiff/worstPeriod; - + this.minDiff = minDiff / bestPeriod; + this.maxDiff = maxDiff / worstPeriod; return bestPeriod; } @@ -316,28 +262,7 @@ import java.util.Arrays; * Returns whether the previous pitch period estimate is a better approximation, which can occur * at the abrupt end of voiced words. */ - private boolean previousPeriodBetter(int minDiff, int maxDiff, boolean preferNewPeriod) { - if (minDiff == 0 || prevPeriod == 0) { - return false; - } - if (preferNewPeriod) { - if (maxDiff > minDiff * 3) { - // Got a reasonable match this period - return false; - } - if (minDiff * 2 <= prevMinDiff * 3) { - // Mismatch is not that much greater this period - return false; - } - } else { - if (minDiff <= prevMinDiff) { - return false; - } - } - return true; - } - - /*private boolean previousPeriodBetter(int minDiff, int maxDiff) { + private boolean previousPeriodBetter(int minDiff, int maxDiff) { if (minDiff == 0 || prevPeriod == 0) { return false; } @@ -350,51 +275,9 @@ import java.util.Arrays; return false; } return true; - }*/ - - private int findPitchPeriod(short samples[], int position, boolean preferNewPeriod) { - int period, retPeriod; - int skip = 1; - - int quality = 1; - if (inputSampleRateHz > AMDF_FREQUENCY && quality == 0) { - skip = inputSampleRateHz / AMDF_FREQUENCY; - } - if (channelCount == 1 && skip == 1) { - period = findPitchPeriodInRange(samples, position, minPeriod, maxPeriod); - } else { - downSampleInput(samples, position, skip); - period = findPitchPeriodInRange(downSampleBuffer, 0, minPeriod / skip, - maxPeriod / skip); - if (skip != 1) { - period *= skip; - int minP = period - (skip << 2); - int maxP = period + (skip << 2); - if (minP < minPeriod) { - minP = minPeriod; - } - if (maxP > maxPeriod) { - maxP = maxPeriod; - } - if (channelCount == 1) { - period = findPitchPeriodInRange(samples, position, minP, maxP); - } else { - downSampleInput(samples, position, 1); - period = findPitchPeriodInRange(downSampleBuffer, 0, minP, maxP); - } - } - } - if (previousPeriodBetter(minDiff, maxDiff, preferNewPeriod)) { - retPeriod = prevPeriod; - } else { - retPeriod = period; - } - prevMinDiff = minDiff; - prevPeriod = period; - return retPeriod; } - /*private int findPitchPeriod(short[] samples, int position) { + private int findPitchPeriod(short[] samples, int position) { // Find the pitch period. This is a critical step, and we may have to try multiple ways to get a // good answer. This version uses AMDF. To improve speed, we down sample by an integer factor // get in the 11 kHz range, and then do it again with a narrower frequency range without down @@ -433,7 +316,7 @@ import java.util.Arrays; prevMinDiff = minDiff; prevPeriod = period; return retPeriod; - }*/ + } private void moveNewSamplesToPitchBuffer(int originalOutputFrameCount) { int frameCount = outputFrameCount - originalOutputFrameCount; @@ -461,78 +344,6 @@ import java.util.Arrays; pitchFrameCount -= frameCount; } - private void adjustPitch(int originalNumOutputSamples) { - int period, newPeriod, separation; - int position = 0; - - if (outputFrameCount == originalNumOutputSamples) { - return; - } - moveNewSamplesToPitchBuffer(originalNumOutputSamples); - while (pitchFrameCount - position >= maxRequiredFrameCount) { - period = findPitchPeriod(pitchBuffer, position, false); - newPeriod = (int) (period / pitch); - outputBuffer = ensureSpaceForAdditionalFrames(outputBuffer, outputFrameCount, newPeriod); - if (pitch >= 1.0f) { - overlapAdd(newPeriod, channelCount, outputBuffer, outputFrameCount, pitchBuffer, - position, pitchBuffer, position + period - newPeriod); - } else { - separation = newPeriod - period; - overlapAddWithSeparation(period, channelCount, separation, outputBuffer, outputFrameCount, - pitchBuffer, position, pitchBuffer, position); - } - outputFrameCount += newPeriod; - position += period; - } - removePitchFrames(position); - } - - // Aproximate the sinc function times a Hann window from the sinc table. - private int findSincCoefficient(int i, int ratio, int width) { - int lobePoints = (SINC_TABLE_SIZE - 1) / SINC_FILTER_POINTS; - int left = i * lobePoints + (ratio * lobePoints) / width; - int right = left + 1; - int position = i * lobePoints * width + ratio * lobePoints - left * width; - int leftVal = sincTable[left]; - int rightVal = sincTable[right]; - - return ((leftVal * (width - position) + rightVal * position) << 1) / width; - } - - // Return 1 if value >= 0, else -1. This represents the sign of value. - private int getSign(int value) { - return value >= 0 ? 1 : 0; - } - - /*private short interpolate(short in[], int inPos, int oldSampleRate, int newSampleRate) { - int i; - int total = 0; - int position = newRatePosition * oldSampleRate; - int leftPosition = oldRatePosition * newSampleRate; - int rightPosition = (oldRatePosition + 1) * newSampleRate; - int ratio = rightPosition - position - 1; - int width = rightPosition - leftPosition; - int weight, value; - int oldSign; - int overflowCount = 0; - - for (i = 0; i < SINC_FILTER_POINTS; i++) { - weight = findSincCoefficient(i, ratio, width); - value = in[inPos + i * channelCount] * weight; - oldSign = getSign(total); - total += value; - if (oldSign != getSign(total) && getSign(value) == oldSign) { - overflowCount += oldSign; - } - } - if (overflowCount > 0) { - return Short.MAX_VALUE; - } else if (overflowCount < 0) { - return Short.MIN_VALUE; - } - return (short) (total >> 16); - }*/ - private short interpolate(short[] in, int inPos, int oldSampleRate, int newSampleRate) { short left = in[inPos]; short right = in[inPos + channelCount]; @@ -544,26 +355,27 @@ import java.util.Arrays; return (short) ((ratio * left + (width - ratio) * right) / width); } - private void adjustRate(float rate, int originalNumOutputSamples) { + private void adjustRate(float rate, int originalOutputFrameCount) { + if (outputFrameCount == originalOutputFrameCount) { + return; + } int newSampleRate = (int) (inputSampleRateHz / rate); int oldSampleRate = inputSampleRateHz; - int position; - - // Set these values to help with the integer math + // Set these values to help with the integer math. while (newSampleRate > (1 << 14) || oldSampleRate > (1 << 14)) { - newSampleRate >>= 1; - oldSampleRate >>= 1; + newSampleRate /= 2; + oldSampleRate /= 2; } - moveNewSamplesToPitchBuffer(originalNumOutputSamples); - // Leave at least one pitch sample in the buffer - for (position = 0; position < pitchFrameCount - 1; position++) { + moveNewSamplesToPitchBuffer(originalOutputFrameCount); + // Leave at least one pitch sample in the buffer. + for (int position = 0; position < pitchFrameCount - 1; position++) { while ((oldRatePosition + 1) * newSampleRate > newRatePosition * oldSampleRate) { outputBuffer = - ensureSpaceForAdditionalFrames( - outputBuffer, outputFrameCount, /* additionalFrameCount= */ 1); + ensureSpaceForAdditionalFrames( + outputBuffer, outputFrameCount, /* additionalFrameCount= */ 1); for (int i = 0; i < channelCount; i++) { - outputBuffer[outputFrameCount * channelCount + i] = interpolate(pitchBuffer, - position * channelCount + i, oldSampleRate, newSampleRate); + outputBuffer[outputFrameCount * channelCount + i] = + interpolate(pitchBuffer, position * channelCount + i, oldSampleRate, newSampleRate); } newRatePosition++; outputFrameCount++; @@ -575,7 +387,7 @@ import java.util.Arrays; newRatePosition = 0; } } - removePitchFrames(position); + removePitchFrames(pitchFrameCount - 1); } private int skipPitchPeriod(short[] samples, int position, float speed, int period) { @@ -635,49 +447,36 @@ import java.util.Arrays; if (inputFrameCount < maxRequiredFrameCount) { return; } - - int numSamples = inputFrameCount; - int position = 0, period, newSamples; - + int frameCount = inputFrameCount; + int positionFrames = 0; do { if (remainingInputToCopyFrameCount > 0) { - newSamples = copyInputToOutput(position); - position += newSamples; + positionFrames += copyInputToOutput(positionFrames); } else { - period = findPitchPeriod(inputBuffer, position, true); + int period = findPitchPeriod(inputBuffer, positionFrames); if (speed > 1.0) { - newSamples = skipPitchPeriod(inputBuffer, position, speed, period); - position += period + newSamples; + positionFrames += period + skipPitchPeriod(inputBuffer, positionFrames, speed, period); } else { - newSamples = insertPitchPeriod(inputBuffer, position, speed, period); - position += newSamples; + positionFrames += insertPitchPeriod(inputBuffer, positionFrames, speed, period); } } - } while (position + maxRequiredFrameCount <= numSamples); - removeProcessedInputFrames(position); + } while (positionFrames + maxRequiredFrameCount <= frameCount); + removeProcessedInputFrames(positionFrames); } private void processStreamInput() { - int originalNumOutputSamples = outputFrameCount; + // Resample as many pitch periods as we have buffered on the input. + int originalOutputFrameCount = outputFrameCount; float s = speed / pitch; - float r = rate; - - boolean useChordPitch = false; - if (!useChordPitch) { - r *= pitch; - } + float r = rate * pitch; if (s > 1.00001 || s < 0.99999) { changeSpeed(s); } else { copyToOutput(inputBuffer, 0, inputFrameCount); inputFrameCount = 0; } - if (useChordPitch) { - if (pitch != 1.0f) { - adjustPitch(originalNumOutputSamples); - } - } else if (r != 1.0f) { - adjustRate(r, originalNumOutputSamples); + if (r != 1.0f) { + adjustRate(r, originalOutputFrameCount); } } @@ -703,35 +502,4 @@ import java.util.Arrays; } } - private static void overlapAddWithSeparation( - int numSamples, - int numChannels, - int separation, - short out[], - int outPos, - short rampDown[], - int rampDownPos, - short rampUp[], - int rampUpPos) - { - for(int i = 0; i < numChannels; i++) { - int o = outPos*numChannels + i; - int u = rampUpPos*numChannels + i; - int d = rampDownPos*numChannels + i; - for(int t = 0; t < numSamples + separation; t++) { - if(t < separation) { - out[o] = (short)(rampDown[d]*(numSamples - t)/numSamples); - d += numChannels; - } else if(t < numSamples) { - out[o] = (short)((rampDown[d]*(numSamples - t) + rampUp[u]*(t - separation))/numSamples); - d += numChannels; - u += numChannels; - } else { - out[o] = (short)(rampUp[u]*(t - separation)/numSamples); - u += numChannels; - } - o += numChannels; - } - } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SonicAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SonicAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java index 6046ea466..2ca2d4782 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/SonicAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.C.Encoding; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.C.Encoding; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/TrimmingAudioProcessor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/TrimmingAudioProcessor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java index 686f8596f..ccaa9c3fe 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/audio/TrimmingAudioProcessor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.audio; +package com.google.android.exoplayer2.audio; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.C.Encoding; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.C.Encoding; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Buffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Buffer.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Buffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Buffer.java index 2a6fa4350..773959fbf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Buffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Buffer.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** * Base class for buffers with flags. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/CryptoInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/CryptoInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java index 743f5629f..ec17de8d7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/CryptoInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; import android.annotation.TargetApi; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; /** * Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Decoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Decoder.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Decoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Decoder.java index 46be86809..7eb1fa1aa 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/Decoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/Decoder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; /** * A media decoder. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderCounters.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderCounters.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderCounters.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderCounters.java index 843724e2f..8409bab55 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderCounters.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderCounters.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; /** * Maintains decoder event counts, for debugging purposes only. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderInputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderInputBuffer.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderInputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderInputBuffer.java index e4b756b45..d22a45ce8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/DecoderInputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/DecoderInputBuffer.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/OutputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/OutputBuffer.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/OutputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/OutputBuffer.java index 5000ebc7e..730ce15ed 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/OutputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/OutputBuffer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; /** * Output buffer decoded by a {@link Decoder}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/SimpleDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/SimpleDecoder.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/SimpleDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/SimpleDecoder.java index 553e1ac30..98b1c7ca0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/decoder/SimpleDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/decoder/SimpleDecoder.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.decoder; +package com.google.android.exoplayer2.decoder; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import java.util.LinkedList; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import java.util.ArrayDeque; /** * Base class for {@link Decoder}s that use their own decode thread. @@ -28,8 +29,8 @@ public abstract class SimpleDecoder queuedInputBuffers; - private final LinkedList queuedOutputBuffers; + private final ArrayDeque queuedInputBuffers; + private final ArrayDeque queuedOutputBuffers; private final I[] availableInputBuffers; private final O[] availableOutputBuffers; @@ -48,8 +49,8 @@ public abstract class SimpleDecoder(); - queuedOutputBuffers = new LinkedList<>(); + queuedInputBuffers = new ArrayDeque<>(); + queuedOutputBuffers = new ArrayDeque<>(); availableInputBuffers = inputBuffers; availableInputBufferCount = inputBuffers.length; for (int i = 0; i < availableInputBufferCount; i++) { @@ -142,7 +143,7 @@ public abstract class SimpleDecoder mediaDrm; private final ProvisioningManager provisioningManager; - private final byte[] initData; - private final String mimeType; + private final SchemeData schemeData; private final @DefaultDrmSessionManager.Mode int mode; private final HashMap optionalKeyRequestParameters; - private final EventDispatcher eventDispatcher; + private final EventDispatcher eventDispatcher; private final int initialDrmRequestRetryCount; /* package */ final MediaDrmCallback callback; @@ -97,15 +97,20 @@ import java.util.UUID; private byte[] sessionId; private byte[] offlineLicenseKeySetId; + private Object currentKeyRequest; + private Object currentProvisionRequest; + /** * Instantiates a new DRM session. * * @param uuid The UUID of the drm scheme. * @param mediaDrm The media DRM. * @param provisioningManager The manager for provisioning. - * @param initData The DRM init data. + * @param schemeData The DRM data for this session, or null if a {@code offlineLicenseKeySetId} is + * provided. * @param mode The DRM mode. - * @param offlineLicenseKeySetId The offlineLicense KeySetId. + * @param offlineLicenseKeySetId The offline license key set identifier, or null when not using + * offline keys. * @param optionalKeyRequestParameters The optional key request parameters. * @param callback The media DRM callback. * @param playbackLooper The playback looper. @@ -117,20 +122,20 @@ import java.util.UUID; UUID uuid, ExoMediaDrm mediaDrm, ProvisioningManager provisioningManager, - byte[] initData, - String mimeType, + @Nullable SchemeData schemeData, @DefaultDrmSessionManager.Mode int mode, - byte[] offlineLicenseKeySetId, + @Nullable byte[] offlineLicenseKeySetId, HashMap optionalKeyRequestParameters, MediaDrmCallback callback, Looper playbackLooper, - EventDispatcher eventDispatcher, + EventDispatcher eventDispatcher, int initialDrmRequestRetryCount) { this.uuid = uuid; this.provisioningManager = provisioningManager; this.mediaDrm = mediaDrm; this.mode = mode; this.offlineLicenseKeySetId = offlineLicenseKeySetId; + this.schemeData = offlineLicenseKeySetId == null ? schemeData : null; this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.callback = callback; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; @@ -141,14 +146,6 @@ import java.util.UUID; requestHandlerThread = new HandlerThread("DrmRequestHandler"); requestHandlerThread.start(); postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper()); - - if (offlineLicenseKeySetId == null) { - this.initData = initData; - this.mimeType = mimeType; - } else { - this.initData = null; - this.mimeType = null; - } } // Life cycle. @@ -177,6 +174,8 @@ import java.util.UUID; requestHandlerThread = null; mediaCrypto = null; lastException = null; + currentKeyRequest = null; + currentProvisionRequest = null; if (sessionId != null) { mediaDrm.closeSession(sessionId); sessionId = null; @@ -187,18 +186,42 @@ import java.util.UUID; } public boolean hasInitData(byte[] initData) { - return Arrays.equals(this.initData, initData); + return Arrays.equals(schemeData != null ? schemeData.data : null, initData); } public boolean hasSessionId(byte[] sessionId) { return Arrays.equals(this.sessionId, sessionId); } + @SuppressWarnings("deprecation") + public void onMediaDrmEvent(int what) { + if (!isOpen()) { + return; + } + switch (what) { + case ExoMediaDrm.EVENT_KEY_REQUIRED: + doLicense(false); + break; + case ExoMediaDrm.EVENT_KEY_EXPIRED: + // When an already expired key is loaded MediaDrm sends this event immediately. Ignore + // this event if the state isn't STATE_OPENED_WITH_KEYS yet which means we're still + // waiting for key response. + onKeysExpired(); + break; + case ExoMediaDrm.EVENT_PROVISION_REQUIRED: + state = STATE_OPENED; + provisioningManager.provisionRequired(this); + break; + default: + break; + } + } + // Provisioning implementation. public void provision() { - ProvisionRequest request = mediaDrm.getProvisionRequest(); - postRequestHandler.obtainMessage(MSG_PROVISION, request, true).sendToTarget(); + currentProvisionRequest = mediaDrm.getProvisionRequest(); + postRequestHandler.post(MSG_PROVISION, currentProvisionRequest, /* allowRetry= */ true); } public void onProvisionCompleted() { @@ -271,11 +294,12 @@ import java.util.UUID; return false; } - private void onProvisionResponse(Object response) { - if (state != STATE_OPENING && !isOpen()) { + private void onProvisionResponse(Object request, Object response) { + if (request != currentProvisionRequest || (state != STATE_OPENING && !isOpen())) { // This event is stale. return; } + currentProvisionRequest = null; if (response instanceof Exception) { provisioningManager.onProvisionError((Exception) response); @@ -309,7 +333,7 @@ import java.util.UUID; onError(new KeysExpiredException()); } else { state = STATE_OPENED_WITH_KEYS; - eventDispatcher.drmKeysRestored(); + eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored); } } break; @@ -356,24 +380,30 @@ import java.util.UUID; private void postKeyRequest(int type, boolean allowRetry) { byte[] scope = type == ExoMediaDrm.KEY_TYPE_RELEASE ? offlineLicenseKeySetId : sessionId; + byte[] initData = null; + String mimeType = null; + String licenseServerUrl = null; + if (schemeData != null) { + initData = schemeData.data; + mimeType = schemeData.mimeType; + licenseServerUrl = schemeData.licenseServerUrl; + } try { - KeyRequest request = mediaDrm.getKeyRequest(scope, initData, mimeType, type, - optionalKeyRequestParameters); - if (C.CLEARKEY_UUID.equals(uuid)) { - request = new DefaultKeyRequest(ClearKeyUtil.adjustRequestData(request.getData()), - request.getDefaultUrl()); - } - postRequestHandler.obtainMessage(MSG_KEYS, request, allowRetry).sendToTarget(); + KeyRequest mediaDrmKeyRequest = + mediaDrm.getKeyRequest(scope, initData, mimeType, type, optionalKeyRequestParameters); + currentKeyRequest = Pair.create(mediaDrmKeyRequest, licenseServerUrl); + postRequestHandler.post(MSG_KEYS, currentKeyRequest, allowRetry); } catch (Exception e) { onKeysError(e); } } - private void onKeyResponse(Object response) { - if (!isOpen()) { + private void onKeyResponse(Object request, Object response) { + if (request != currentKeyRequest || !isOpen()) { // This event is stale. return; } + currentKeyRequest = null; if (response instanceof Exception) { onKeysError((Exception) response); @@ -382,12 +412,9 @@ import java.util.UUID; try { byte[] responseData = (byte[]) response; - if (C.CLEARKEY_UUID.equals(uuid)) { - responseData = ClearKeyUtil.adjustResponseData(responseData); - } if (mode == DefaultDrmSessionManager.MODE_RELEASE) { mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData); - eventDispatcher.drmKeysRemoved(); + eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored); } else { byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData); if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD @@ -396,7 +423,7 @@ import java.util.UUID; offlineLicenseKeySetId = keySetId; } state = STATE_OPENED_WITH_KEYS; - eventDispatcher.drmKeysLoaded(); + eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysLoaded); } } catch (Exception e) { onKeysError(e); @@ -420,7 +447,7 @@ import java.util.UUID; private void onError(final Exception e) { lastException = new DrmSessionException(e); - eventDispatcher.drmSessionManagerError(e); + eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(e)); if (state != STATE_OPENED_WITH_KEYS) { state = STATE_ERROR; } @@ -430,30 +457,7 @@ import java.util.UUID; return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS; } - @SuppressWarnings("deprecation") - public void onMediaDrmEvent(int what) { - if (!isOpen()) { - return; - } - switch (what) { - case ExoMediaDrm.EVENT_KEY_REQUIRED: - doLicense(false); - break; - case ExoMediaDrm.EVENT_KEY_EXPIRED: - // When an already expired key is loaded MediaDrm sends this event immediately. Ignore - // this event if the state isn't STATE_OPENED_WITH_KEYS yet which means we're still - // waiting for key response. - onKeysExpired(); - break; - case ExoMediaDrm.EVENT_PROVISION_REQUIRED: - state = STATE_OPENED; - provisioningManager.provisionRequired(this); - break; - default: - break; - } - - } + // Internal classes. @SuppressLint("HandlerLeak") private class PostResponseHandler extends Handler { @@ -464,12 +468,15 @@ import java.util.UUID; @Override public void handleMessage(Message msg) { + Pair requestAndResponse = (Pair) msg.obj; + Object request = requestAndResponse.first; + Object response = requestAndResponse.second; switch (msg.what) { case MSG_PROVISION: - onProvisionResponse(msg.obj); + onProvisionResponse(request, response); break; case MSG_KEYS: - onKeyResponse(msg.obj); + onKeyResponse(request, response); break; default: break; @@ -486,21 +493,27 @@ import java.util.UUID; super(backgroundLooper); } - Message obtainMessage(int what, Object object, boolean allowRetry) { - return obtainMessage(what, allowRetry ? 1 : 0 /* allow retry*/, 0 /* error count */, - object); + void post(int what, Object request, boolean allowRetry) { + int allowRetryInt = allowRetry ? 1 : 0; + int errorCount = 0; + obtainMessage(what, allowRetryInt, errorCount, request).sendToTarget(); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message msg) { + Object request = msg.obj; Object response; try { switch (msg.what) { case MSG_PROVISION: - response = callback.executeProvisionRequest(uuid, (ProvisionRequest) msg.obj); + response = callback.executeProvisionRequest(uuid, (ProvisionRequest) request); break; case MSG_KEYS: - response = callback.executeKeyRequest(uuid, (KeyRequest) msg.obj); + Pair keyRequest = (Pair) request; + KeyRequest mediaDrmKeyRequest = keyRequest.first; + String licenseServerUrl = keyRequest.second; + response = callback.executeKeyRequest(uuid, mediaDrmKeyRequest, licenseServerUrl); break; default: throw new RuntimeException(); @@ -511,7 +524,7 @@ import java.util.UUID; } response = e; } - postResponseHandler.obtainMessage(msg.what, response).sendToTarget(); + postResponseHandler.obtainMessage(msg.what, Pair.create(request, response)).sendToTarget(); } private boolean maybeRetryRequest(Message originalMsg) { @@ -534,5 +547,4 @@ import java.util.UUID; } } - } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java new file mode 100755 index 000000000..afec4b611 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.drm; + +import com.google.android.exoplayer2.Player; + +/** Listener of {@link DefaultDrmSessionManager} events. */ +public interface DefaultDrmSessionEventListener { + + /** Called each time keys are loaded. */ + void onDrmKeysLoaded(); + + /** + * Called when a drm error occurs. + * + *

    This method being called does not indicate that playback has failed, or that it will fail. + * The player may be able to recover from the error and continue. Hence applications should + * not implement this method to display a user visible error or initiate an application + * level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement + * such behavior). This method is called to provide the application with an opportunity to log the + * error if it wishes to do so. + * + * @param error The corresponding exception. + */ + void onDrmSessionManagerError(Exception error); + + /** Called each time offline keys are restored. */ + void onDrmKeysRestored(); + + /** Called each time offline keys are removed. */ + void onDrmKeysRemoved(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionManager.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionManager.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index 292287b0f..895c27ad9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -24,16 +24,15 @@ import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.drm.DefaultDrmSession.ProvisioningManager; -import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.OnEventListener; -import org.telegram.messenger.exoplayer2.extractor.mp4.PsshAtomUtil; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; +import com.google.android.exoplayer2.drm.ExoMediaDrm.OnEventListener; +import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.EventDispatcher; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -89,13 +88,12 @@ public class DefaultDrmSessionManager implements DrmSe public static final int INITIAL_DRM_REQUEST_RETRY_COUNT = 3; private static final String TAG = "DefaultDrmSessionMgr"; - private static final String CENC_SCHEME_MIME_TYPE = "cenc"; private final UUID uuid; private final ExoMediaDrm mediaDrm; private final MediaDrmCallback callback; private final HashMap optionalKeyRequestParameters; - private final EventDispatcher eventDispatcher; + private final EventDispatcher eventDispatcher; private final boolean multiSession; private final int initialDrmRequestRetryCount; @@ -356,7 +354,7 @@ public class DefaultDrmSessionManager implements DrmSe this.mediaDrm = mediaDrm; this.callback = callback; this.optionalKeyRequestParameters = optionalKeyRequestParameters; - this.eventDispatcher = new EventDispatcher(); + this.eventDispatcher = new EventDispatcher<>(); this.multiSession = multiSession; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; mode = MODE_PLAYBACK; @@ -509,17 +507,14 @@ public class DefaultDrmSessionManager implements DrmSe } } - byte[] initData = null; - String mimeType = null; + SchemeData schemeData = null; if (offlineLicenseKeySetId == null) { - SchemeData data = getSchemeData(drmInitData, uuid, false); - if (data == null) { + schemeData = getSchemeData(drmInitData, uuid, false); + if (schemeData == null) { final MissingSchemeDataException error = new MissingSchemeDataException(uuid); - eventDispatcher.drmSessionManagerError(error); + eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(error)); return new ErrorStateDrmSession<>(new DrmSessionException(error)); } - initData = getSchemeInitData(data, uuid); - mimeType = getSchemeMimeType(data, uuid); } DefaultDrmSession session; @@ -528,6 +523,7 @@ public class DefaultDrmSessionManager implements DrmSe } else { // Only use an existing session if it has matching init data. session = null; + byte[] initData = schemeData != null ? schemeData.data : null; for (DefaultDrmSession existingSession : sessions) { if (existingSession.hasInitData(initData)) { session = existingSession; @@ -543,8 +539,7 @@ public class DefaultDrmSessionManager implements DrmSe uuid, mediaDrm, this, - initData, - mimeType, + schemeData, mode, offlineLicenseKeySetId, optionalKeyRequestParameters, @@ -650,31 +645,6 @@ public class DefaultDrmSessionManager implements DrmSe return matchingSchemeDatas.get(0); } - private static byte[] getSchemeInitData(SchemeData data, UUID uuid) { - byte[] schemeInitData = data.data; - if (Util.SDK_INT < 21) { - // Prior to L the Widevine CDM required data to be extracted from the PSSH atom. - byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeInitData, uuid); - if (psshData == null) { - // Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged. - } else { - schemeInitData = psshData; - } - } - return schemeInitData; - } - - private static String getSchemeMimeType(SchemeData data, UUID uuid) { - String schemeMimeType = data.mimeType; - if (Util.SDK_INT < 26 && C.CLEARKEY_UUID.equals(uuid) - && (MimeTypes.VIDEO_MP4.equals(schemeMimeType) - || MimeTypes.AUDIO_MP4.equals(schemeMimeType))) { - // Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4. - schemeMimeType = CENC_SCHEME_MIME_TYPE; - } - return schemeMimeType; - } - @SuppressLint("HandlerLeak") private class MediaDrmHandler extends Handler { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmInitData.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmInitData.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java index cb907fd10..cd7adea1e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmInitData.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -266,9 +266,9 @@ public final class DrmInitData implements Comparator, Parcelable { * applies to all schemes). */ private final UUID uuid; - /** - * The mimeType of {@link #data}. - */ + /** The URL of the server to which license requests should be made. May be null if unknown. */ + public final @Nullable String licenseServerUrl; + /** The mimeType of {@link #data}. */ public final String mimeType; /** * The initialization data. May be null for scheme support checks only. @@ -297,7 +297,25 @@ public final class DrmInitData implements Comparator, Parcelable { * @param requiresSecureDecryption See {@link #requiresSecureDecryption}. */ public SchemeData(UUID uuid, String mimeType, byte[] data, boolean requiresSecureDecryption) { + this(uuid, /* licenseServerUrl= */ null, mimeType, data, requiresSecureDecryption); + } + + /** + * @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is + * universal (i.e. applies to all schemes). + * @param licenseServerUrl See {@link #licenseServerUrl}. + * @param mimeType See {@link #mimeType}. + * @param data See {@link #data}. + * @param requiresSecureDecryption See {@link #requiresSecureDecryption}. + */ + public SchemeData( + UUID uuid, + @Nullable String licenseServerUrl, + String mimeType, + byte[] data, + boolean requiresSecureDecryption) { this.uuid = Assertions.checkNotNull(uuid); + this.licenseServerUrl = licenseServerUrl; this.mimeType = Assertions.checkNotNull(mimeType); this.data = data; this.requiresSecureDecryption = requiresSecureDecryption; @@ -305,6 +323,7 @@ public final class DrmInitData implements Comparator, Parcelable { /* package */ SchemeData(Parcel in) { uuid = new UUID(in.readLong(), in.readLong()); + licenseServerUrl = in.readString(); mimeType = in.readString(); data = in.createByteArray(); requiresSecureDecryption = in.readByte() != 0; @@ -346,7 +365,9 @@ public final class DrmInitData implements Comparator, Parcelable { return true; } SchemeData other = (SchemeData) obj; - return mimeType.equals(other.mimeType) && Util.areEqual(uuid, other.uuid) + return Util.areEqual(licenseServerUrl, other.licenseServerUrl) + && Util.areEqual(mimeType, other.mimeType) + && Util.areEqual(uuid, other.uuid) && Arrays.equals(data, other.data); } @@ -354,6 +375,7 @@ public final class DrmInitData implements Comparator, Parcelable { public int hashCode() { if (hashCode == 0) { int result = uuid.hashCode(); + result = 31 * result + (licenseServerUrl == null ? 0 : licenseServerUrl.hashCode()); result = 31 * result + mimeType.hashCode(); result = 31 * result + Arrays.hashCode(data); hashCode = result; @@ -372,6 +394,7 @@ public final class DrmInitData implements Comparator, Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeLong(uuid.getMostSignificantBits()); dest.writeLong(uuid.getLeastSignificantBits()); + dest.writeString(licenseServerUrl); dest.writeString(mimeType); dest.writeByteArray(data); dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSession.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSession.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java index b8fef9d67..a3ae1d8b7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSession.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.TargetApi; import android.media.MediaDrm; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSessionManager.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSessionManager.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java index 644274ab4..cf3d97d0b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DrmSessionManager.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.TargetApi; import android.os.Looper; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; /** * Manages a DRM session. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ErrorStateDrmSession.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ErrorStateDrmSession.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ErrorStateDrmSession.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ErrorStateDrmSession.java index a4ab1b987..d30e670c3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ErrorStateDrmSession.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ErrorStateDrmSession.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.util.Map; /** A {@link DrmSession} that's in a terminal error state. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaCrypto.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaCrypto.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaCrypto.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaCrypto.java index 4eaffb894..d5a4f6add 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaCrypto.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaCrypto.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; /** * An opaque {@link android.media.MediaCrypto} equivalent. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaDrm.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaDrm.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaDrm.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaDrm.java index e94f40d04..2699559c5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/ExoMediaDrm.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/ExoMediaDrm.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.media.DeniedByServerException; import android.media.MediaCryptoException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaCrypto.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaCrypto.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java index 6be560669..4e58ed6a3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaCrypto.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.TargetApi; import android.media.MediaCrypto; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; /** * An {@link ExoMediaCrypto} implementation that wraps the framework {@link MediaCrypto}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaDrm.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java similarity index 74% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaDrm.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java index 0fb0e6712..c87e82f97 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/FrameworkMediaDrm.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.TargetApi; import android.media.DeniedByServerException; @@ -25,9 +25,11 @@ import android.media.NotProvisionedException; import android.media.UnsupportedSchemeException; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -40,6 +42,8 @@ import java.util.UUID; @TargetApi(23) public final class FrameworkMediaDrm implements ExoMediaDrm { + private static final String CENC_SCHEME_MIME_TYPE = "cenc"; + private final UUID uuid; private final MediaDrm mediaDrm; @@ -67,6 +71,9 @@ public final class FrameworkMediaDrm implements ExoMediaDrm optionalParameters) throws NotProvisionedException { + + // Prior to L the Widevine CDM required data to be extracted from the PSSH atom. Some Amazon + // devices also required data to be extracted from the PSSH atom for PlayReady. + if ((Util.SDK_INT < 21 && C.WIDEVINE_UUID.equals(uuid)) + || (C.PLAYREADY_UUID.equals(uuid) + && "Amazon".equals(Util.MANUFACTURER) + && ("AFTB".equals(Util.MODEL) // Fire TV Gen 1 + || "AFTS".equals(Util.MODEL) // Fire TV Gen 2 + || "AFTM".equals(Util.MODEL)))) { // Fire TV Stick Gen 1 + byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(init, uuid); + if (psshData == null) { + // Extraction failed. schemeData isn't a PSSH atom, so leave it unchanged. + } else { + init = psshData; + } + } + + // Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4. + if (Util.SDK_INT < 26 + && C.CLEARKEY_UUID.equals(uuid) + && (MimeTypes.VIDEO_MP4.equals(mimeType) || MimeTypes.AUDIO_MP4.equals(mimeType))) { + mimeType = CENC_SCHEME_MIME_TYPE; + } + final MediaDrm.KeyRequest request = mediaDrm.getKeyRequest(scope, init, mimeType, keyType, optionalParameters); - return new DefaultKeyRequest(request.getData(), request.getDefaultUrl()); + + byte[] requestData = request.getData(); + if (C.CLEARKEY_UUID.equals(uuid)) { + requestData = ClearKeyUtil.adjustRequestData(requestData); + } + + return new DefaultKeyRequest(requestData, request.getDefaultUrl()); } @Override public byte[] provideKeyResponse(byte[] scope, byte[] response) throws NotProvisionedException, DeniedByServerException { + + if (C.CLEARKEY_UUID.equals(uuid)) { + response = ClearKeyUtil.adjustResponseData(response); + } + return mediaDrm.provideKeyResponse(scope, response); } @@ -183,4 +225,12 @@ public final class FrameworkMediaDrm implements ExoMediaDrmSee GitHub issue #4413. + */ + private static boolean needsForceL3Workaround() { + return "ASUS_Z00AD".equals(Util.MODEL); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/HttpMediaDrmCallback.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/HttpMediaDrmCallback.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java index b440c9047..fc1e62a89 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/HttpMediaDrmCallback.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.annotation.TargetApi; import android.net.Uri; +import android.support.annotation.Nullable; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; -import org.telegram.messenger.exoplayer2.upstream.DataSourceInputStream; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; +import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; +import com.google.android.exoplayer2.upstream.DataSourceInputStream; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.HttpDataSource; +import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.HashMap; import java.util.List; @@ -108,13 +109,19 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback { @Override public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException { - String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); + String url = + request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData()); return executePost(dataSourceFactory, url, new byte[0], null); } @Override - public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception { + public byte[] executeKeyRequest( + UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl) + throws Exception { String url = request.getDefaultUrl(); + if (TextUtils.isEmpty(url)) { + url = mediaProvidedLicenseServerUrl; + } if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) { url = defaultLicenseUrl; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/KeysExpiredException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/KeysExpiredException.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/KeysExpiredException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/KeysExpiredException.java index 9fb1ade97..e5e1089fa 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/KeysExpiredException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/KeysExpiredException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; /** * Thrown when the drm keys loaded into an open session expire. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/LocalMediaDrmCallback.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/LocalMediaDrmCallback.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/LocalMediaDrmCallback.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/LocalMediaDrmCallback.java index 54d75560b..7ed4a61a6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/LocalMediaDrmCallback.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/LocalMediaDrmCallback.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; +import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.UUID; @@ -44,7 +45,9 @@ public final class LocalMediaDrmCallback implements MediaDrmCallback { } @Override - public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception { + public byte[] executeKeyRequest( + UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl) + throws Exception { return keyResponse; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/MediaDrmCallback.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/MediaDrmCallback.java similarity index 68% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/MediaDrmCallback.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/MediaDrmCallback.java index 32aae7961..4405d6e53 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/MediaDrmCallback.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/MediaDrmCallback.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest; -import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; +import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import java.util.UUID; /** @@ -38,10 +39,13 @@ public interface MediaDrmCallback { * Executes a key request. * * @param uuid The UUID of the content protection scheme. - * @param request The request. + * @param request The request generated by the content decryption module. + * @param mediaProvidedLicenseServerUrl A license server URL provided by the media, or null if the + * media does not include any license server URL. * @return The response data. * @throws Exception If an error occurred executing the request. */ - byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception; - + byte[] executeKeyRequest( + UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl) + throws Exception; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/OfflineLicenseHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/OfflineLicenseHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java index 97dc99b0f..9298c16cb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/OfflineLicenseHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.media.MediaDrm; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager.Mode; -import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.Factory; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; +import com.google.android.exoplayer2.upstream.HttpDataSource; +import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; +import com.google.android.exoplayer2.util.Assertions; import java.util.HashMap; import java.util.UUID; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/UnsupportedDrmException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/UnsupportedDrmException.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/UnsupportedDrmException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/UnsupportedDrmException.java index 6c8c66fad..f0e748d72 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/UnsupportedDrmException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/UnsupportedDrmException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.support.annotation.IntDef; import java.lang.annotation.Retention; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/WidevineUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/WidevineUtil.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/WidevineUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/WidevineUtil.java index 21a9e159f..45c38b360 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/WidevineUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/drm/WidevineUtil.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.drm; +package com.google.android.exoplayer2.drm; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.util.Map; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java similarity index 60% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java index dc84bd5a3..63b8d9bb8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java @@ -13,42 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.ffmpeg; +package com.google.android.exoplayer2.ext.ffmpeg; import android.os.Handler; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.AudioProcessor; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.audio.AudioSink; -import org.telegram.messenger.exoplayer2.audio.DefaultAudioSink; -import org.telegram.messenger.exoplayer2.audio.SimpleDecoderAudioRenderer; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.AudioProcessor; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.AudioSink; +import com.google.android.exoplayer2.audio.DefaultAudioSink; +import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import java.util.Collections; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Decodes and renders audio using FFmpeg. */ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { - /** - * The number of input and output buffers. - */ + /** The number of input and output buffers. */ private static final int NUM_BUFFERS = 16; - /** - * The initial input buffer size. Input buffers are reallocated dynamically if this value is - * insufficient. - */ - private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6; + /** The default input buffer size. */ + private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; private final boolean enableFloatOutput; - private FfmpegDecoder decoder; + private @MonotonicNonNull FfmpegDecoder decoder; public FfmpegAudioRenderer() { - this(null, null); + this(/* eventHandler= */ null, /* eventListener= */ null); } /** @@ -57,9 +56,15 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { * @param eventListener A listener of events. May be null if delivery of events is not required. * @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. */ - public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, + public FfmpegAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, AudioProcessor... audioProcessors) { - this(eventHandler, eventListener, new DefaultAudioSink(null, audioProcessors), false); + this( + eventHandler, + eventListener, + new DefaultAudioSink(/* audioCapabilities= */ null, audioProcessors), + /* enableFloatOutput= */ false); } /** @@ -72,8 +77,11 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { * 32-bit float output, any audio processing will be disabled, including playback speed/pitch * adjustment. */ - public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, - AudioSink audioSink, boolean enableFloatOutput) { + public FfmpegAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, + AudioSink audioSink, + boolean enableFloatOutput) { super( eventHandler, eventListener, @@ -86,10 +94,11 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { @Override protected int supportsFormatInternal(DrmSessionManager drmSessionManager, Format format) { - String sampleMimeType = format.sampleMimeType; - if (!MimeTypes.isAudio(sampleMimeType)) { + Assertions.checkNotNull(format.sampleMimeType); + if (!MimeTypes.isAudio(format.sampleMimeType)) { return FORMAT_UNSUPPORTED_TYPE; - } else if (!FfmpegLibrary.supportsFormat(sampleMimeType) || !isOutputSupported(format)) { + } else if (!FfmpegLibrary.supportsFormat(format.sampleMimeType, format.pcmEncoding) + || !isOutputSupported(format)) { return FORMAT_UNSUPPORTED_SUBTYPE; } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { return FORMAT_UNSUPPORTED_DRM; @@ -106,18 +115,33 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { @Override protected FfmpegDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto) throws FfmpegDecoderException { - decoder = new FfmpegDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, - format.sampleMimeType, format.initializationData, shouldUseFloatOutput(format)); + int initialInputBufferSize = + format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; + decoder = + new FfmpegDecoder( + NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, format, shouldUseFloatOutput(format)); return decoder; } @Override public Format getOutputFormat() { + Assertions.checkNotNull(decoder); int channelCount = decoder.getChannelCount(); int sampleRate = decoder.getSampleRate(); @C.PcmEncoding int encoding = decoder.getEncoding(); - return Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, null, Format.NO_VALUE, - Format.NO_VALUE, channelCount, sampleRate, encoding, null, null, 0, null); + return Format.createAudioSampleFormat( + /* id= */ null, + MimeTypes.AUDIO_RAW, + /* codecs= */ null, + Format.NO_VALUE, + Format.NO_VALUE, + channelCount, + sampleRate, + encoding, + Collections.emptyList(), + /* drmInitData= */ null, + /* selectionFlags= */ 0, + /* language= */ null); } private boolean isOutputSupported(Format inputFormat) { @@ -125,6 +149,7 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { } private boolean shouldUseFloatOutput(Format inputFormat) { + Assertions.checkNotNull(inputFormat.sampleMimeType); if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java index ee394c309..1cfaabb7a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java @@ -13,14 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.ffmpeg; +package com.google.android.exoplayer2.ext.ffmpeg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; -import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.decoder.SimpleDecoder; +import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.nio.ByteBuffer; import java.util.List; @@ -30,13 +33,12 @@ import java.util.List; /* package */ final class FfmpegDecoder extends SimpleDecoder { - // Space for 64 ms of 48 kHz 8 channel 16-bit PCM audio. - private static final int OUTPUT_BUFFER_SIZE_16BIT = 64 * 48 * 8 * 2; - // Space for 64 ms of 48 KhZ 8 channel 32-bit PCM audio. + // Output buffer sizes when decoding PCM mu-law streams, which is the maximum FFmpeg outputs. + private static final int OUTPUT_BUFFER_SIZE_16BIT = 65536; private static final int OUTPUT_BUFFER_SIZE_32BIT = OUTPUT_BUFFER_SIZE_16BIT * 2; private final String codecName; - private final byte[] extraData; + private final @Nullable byte[] extraData; private final @C.Encoding int encoding; private final int outputBufferSize; @@ -45,15 +47,23 @@ import java.util.List; private volatile int channelCount; private volatile int sampleRate; - public FfmpegDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, - String mimeType, List initializationData, boolean outputFloat) + public FfmpegDecoder( + int numInputBuffers, + int numOutputBuffers, + int initialInputBufferSize, + Format format, + boolean outputFloat) throws FfmpegDecoderException { super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]); - codecName = FfmpegLibrary.getCodecName(mimeType); - extraData = getExtraData(mimeType, initializationData); + Assertions.checkNotNull(format.sampleMimeType); + codecName = + Assertions.checkNotNull( + FfmpegLibrary.getCodecName(format.sampleMimeType, format.pcmEncoding)); + extraData = getExtraData(format.sampleMimeType, format.initializationData); encoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT; outputBufferSize = outputFloat ? OUTPUT_BUFFER_SIZE_32BIT : OUTPUT_BUFFER_SIZE_16BIT; - nativeContext = ffmpegInitialize(codecName, extraData, outputFloat); + nativeContext = + ffmpegInitialize(codecName, extraData, outputFloat, format.sampleRate, format.channelCount); if (nativeContext == 0) { throw new FfmpegDecoderException("Initialization failed."); } @@ -81,7 +91,7 @@ import java.util.List; } @Override - protected FfmpegDecoderException decode( + protected @Nullable FfmpegDecoderException decode( DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) { if (reset) { nativeContext = ffmpegReset(nativeContext, extraData); @@ -100,6 +110,7 @@ import java.util.List; channelCount = ffmpegGetChannelCount(nativeContext); sampleRate = ffmpegGetSampleRate(nativeContext); if (sampleRate == 0 && "alac".equals(codecName)) { + Assertions.checkNotNull(extraData); // ALAC decoder did not set the sample rate in earlier versions of FFMPEG. // See https://trac.ffmpeg.org/ticket/6096 ParsableByteArray parsableExtraData = new ParsableByteArray(extraData); @@ -145,7 +156,7 @@ import java.util.List; * Returns FFmpeg-compatible codec-specific initialization data ("extra data"), or {@code null} if * not required. */ - private static byte[] getExtraData(String mimeType, List initializationData) { + private static @Nullable byte[] getExtraData(String mimeType, List initializationData) { switch (mimeType) { case MimeTypes.AUDIO_AAC: case MimeTypes.AUDIO_ALAC: @@ -170,12 +181,20 @@ import java.util.List; } } - private native long ffmpegInitialize(String codecName, byte[] extraData, boolean outputFloat); + private native long ffmpegInitialize( + String codecName, + @Nullable byte[] extraData, + boolean outputFloat, + int rawSampleRate, + int rawChannelCount); + private native int ffmpegDecode(long context, ByteBuffer inputData, int inputSize, ByteBuffer outputData, int outputSize); private native int ffmpegGetChannelCount(long context); private native int ffmpegGetSampleRate(long context); - private native long ffmpegReset(long context, byte[] extraData); + + private native long ffmpegReset(long context, @Nullable byte[] extraData); + private native void ffmpegRelease(long context); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java index 812c91814..d6b5a6245 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoderException.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.ffmpeg; +package com.google.android.exoplayer2.ext.ffmpeg; -import org.telegram.messenger.exoplayer2.audio.AudioDecoderException; +import com.google.android.exoplayer2.audio.AudioDecoderException; /** * Thrown when an FFmpeg decoder error occurs. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegLibrary.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java similarity index 67% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegLibrary.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java index 76aef73b2..5926b7e0d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/ffmpeg/FfmpegLibrary.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.ffmpeg; +package com.google.android.exoplayer2.ext.ffmpeg; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.util.LibraryLoader; +import com.google.android.exoplayer2.util.MimeTypes; /** * Configures and queries the underlying native library. @@ -29,10 +32,8 @@ public final class FfmpegLibrary { private FfmpegLibrary() {} - /** - * Returns the version of the underlying library if available, or null otherwise. - */ - public static String getVersion() { + /** Returns the version of the underlying library if available, or null otherwise. */ + public static @Nullable String getVersion() { return ffmpegGetVersion(); } @@ -40,16 +41,18 @@ public final class FfmpegLibrary { * Returns whether the underlying library supports the specified MIME type. * * @param mimeType The MIME type to check. + * @param encoding The PCM encoding for raw audio. */ - public static boolean supportsFormat(String mimeType) { - String codecName = getCodecName(mimeType); + public static boolean supportsFormat(String mimeType, @C.PcmEncoding int encoding) { + String codecName = getCodecName(mimeType, encoding); return codecName != null && ffmpegHasDecoder(codecName); } /** - * Returns the name of the FFmpeg decoder that could be used to decode {@code mimeType}. + * Returns the name of the FFmpeg decoder that could be used to decode the format, or {@code null} + * if it's unsupported. */ - /* package */ static String getCodecName(String mimeType) { + /* package */ static @Nullable String getCodecName(String mimeType, @C.PcmEncoding int encoding) { switch (mimeType) { case MimeTypes.AUDIO_AAC: return "aac"; @@ -78,6 +81,14 @@ public final class FfmpegLibrary { return "flac"; case MimeTypes.AUDIO_ALAC: return "alac"; + case MimeTypes.AUDIO_RAW: + if (encoding == C.ENCODING_PCM_MU_LAW) { + return "pcm_mulaw"; + } else if (encoding == C.ENCODING_PCM_A_LAW) { + return "pcm_alaw"; + } else { + return null; + } default: return null; } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeeker.java new file mode 100755 index 000000000..269d50432 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeeker.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.flac; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.BinarySearchSeeker; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.FlacStreamInfo; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A {@link SeekMap} implementation for FLAC stream using binary search. + * + *

    This seeker performs seeking by using binary search within the stream, until it finds the + * frame that contains the target sample. + */ +/* package */ final class FlacBinarySearchSeeker extends BinarySearchSeeker { + + private final FlacDecoderJni decoderJni; + + public FlacBinarySearchSeeker( + FlacStreamInfo streamInfo, + long firstFramePosition, + long inputLength, + FlacDecoderJni decoderJni) { + super( + new FlacSeekTimestampConverter(streamInfo), + new FlacTimestampSeeker(decoderJni), + streamInfo.durationUs(), + /* floorTimePosition= */ 0, + /* ceilingTimePosition= */ streamInfo.totalSamples, + /* floorBytePosition= */ firstFramePosition, + /* ceilingBytePosition= */ inputLength, + /* approxBytesPerFrame= */ streamInfo.getApproxBytesPerFrame(), + /* minimumSearchRange= */ Math.max(1, streamInfo.minFrameSize)); + this.decoderJni = Assertions.checkNotNull(decoderJni); + } + + @Override + protected void onSeekOperationFinished(boolean foundTargetFrame, long resultPosition) { + if (!foundTargetFrame) { + // If we can't find the target frame (sample), we need to reset the decoder jni so that + // it can continue from the result position. + decoderJni.reset(resultPosition); + } + } + + private static final class FlacTimestampSeeker implements TimestampSeeker { + + private final FlacDecoderJni decoderJni; + + private FlacTimestampSeeker(FlacDecoderJni decoderJni) { + this.decoderJni = decoderJni; + } + + @Override + public TimestampSearchResult searchForTimestamp( + ExtractorInput input, long targetSampleIndex, OutputFrameHolder outputFrameHolder) + throws IOException, InterruptedException { + ByteBuffer outputBuffer = outputFrameHolder.byteBuffer; + long searchPosition = input.getPosition(); + int searchRangeBytes = getTimestampSearchBytesRange(); + decoderJni.reset(searchPosition); + try { + decoderJni.decodeSampleWithBacktrackPosition( + outputBuffer, /* retryPosition= */ searchPosition); + } catch (FlacDecoderJni.FlacFrameDecodeException e) { + // For some reasons, the extractor can't find a frame mid-stream. + // Stop the seeking and let it re-try playing at the last search position. + return TimestampSearchResult.NO_TIMESTAMP_IN_RANGE_RESULT; + } + if (outputBuffer.limit() == 0) { + return TimestampSearchResult.NO_TIMESTAMP_IN_RANGE_RESULT; + } + + long lastFrameSampleIndex = decoderJni.getLastFrameFirstSampleIndex(); + long nextFrameSampleIndex = decoderJni.getNextFrameFirstSampleIndex(); + long nextFrameSamplePosition = decoderJni.getDecodePosition(); + + boolean targetSampleInLastFrame = + lastFrameSampleIndex <= targetSampleIndex && nextFrameSampleIndex > targetSampleIndex; + + if (targetSampleInLastFrame) { + // We are holding the target frame in outputFrameHolder. Set its presentation time now. + outputFrameHolder.timeUs = decoderJni.getLastFrameTimestamp(); + return TimestampSearchResult.targetFoundResult(input.getPosition()); + } else if (nextFrameSampleIndex <= targetSampleIndex) { + return TimestampSearchResult.underestimatedResult( + nextFrameSampleIndex, nextFrameSamplePosition); + } else { + return TimestampSearchResult.overestimatedResult(lastFrameSampleIndex, searchPosition); + } + } + + @Override + public int getTimestampSearchBytesRange() { + // We rely on decoderJni to search for timestamp (sample index) from a given stream point, so + // we don't restrict the range at all. + return C.LENGTH_UNSET; + } + } + + /** + * A {@link SeekTimestampConverter} implementation that returns the frame index (sample index) as + * the timestamp for a stream seek time position. + */ + private static final class FlacSeekTimestampConverter implements SeekTimestampConverter { + private final FlacStreamInfo streamInfo; + + public FlacSeekTimestampConverter(FlacStreamInfo streamInfo) { + this.streamInfo = streamInfo; + } + + @Override + public long timeUsToTargetTime(long timeUs) { + return Assertions.checkNotNull(streamInfo).getSampleIndex(timeUs); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java index f70223bdf..2d74bce5f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.flac; +package com.google.android.exoplayer2.ext.flac; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; -import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer; -import org.telegram.messenger.exoplayer2.util.FlacStreamInfo; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.decoder.SimpleDecoder; +import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; +import com.google.android.exoplayer2.util.FlacStreamInfo; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; @@ -37,11 +38,17 @@ import java.util.List; * * @param numInputBuffers The number of input buffers. * @param numOutputBuffers The number of output buffers. + * @param maxInputBufferSize The maximum required input buffer size if known, or {@link + * Format#NO_VALUE} otherwise. * @param initializationData Codec-specific initialization data. It should contain only one entry - * which is the flac file header. + * which is the flac file header. * @throws FlacDecoderException Thrown if an exception occurs when initializing the decoder. */ - public FlacDecoder(int numInputBuffers, int numOutputBuffers, List initializationData) + public FlacDecoder( + int numInputBuffers, + int numOutputBuffers, + int maxInputBufferSize, + List initializationData) throws FlacDecoderException { super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]); if (initializationData.size() != 1) { @@ -60,7 +67,9 @@ import java.util.List; throw new FlacDecoderException("Metadata decoding failed"); } - setInitialInputBufferSize(streamInfo.maxFrameSize); + int initialInputBufferSize = + maxInputBufferSize != Format.NO_VALUE ? maxInputBufferSize : streamInfo.maxFrameSize; + setInitialInputBufferSize(initialInputBufferSize); maxOutputBufferSize = streamInfo.maxDecodedFrameSize(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderException.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderException.java index 6632d6330..95d7f87c0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderException.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.flac; +package com.google.android.exoplayer2.ext.flac; -import org.telegram.messenger.exoplayer2.audio.AudioDecoderException; +import com.google.android.exoplayer2.audio.AudioDecoderException; /** * Thrown when an Flac decoder error occurs. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderJni.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderJni.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java index f5a5651f7..c85c7874c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacDecoderJni.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java @@ -13,17 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.flac; +package com.google.android.exoplayer2.ext.flac; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.FlacStreamInfo; +import android.support.annotation.Keep; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.FlacStreamInfo; import java.io.IOException; import java.nio.ByteBuffer; /** * JNI wrapper for the libflac Flac decoder. */ +@Keep /* package */ final class FlacDecoderJni { /** Exception to be thrown if {@link #decodeSample(ByteBuffer)} fails to decode a frame. */ @@ -97,6 +100,7 @@ import java.nio.ByteBuffer; * @return Returns the number of bytes read, or -1 on failure. It's not an error if this returns * zero; it just means all the data read from the source. */ + @Keep public int read(ByteBuffer target) throws IOException, InterruptedException { int byteCount = target.remaining(); if (byteBufferData != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java index a5f97a429..b6eec765d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java @@ -13,28 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.flac; +package com.google.android.exoplayer2.ext.flac; -import static org.telegram.messenger.exoplayer2.util.Util.getPcmEncoding; +import static com.google.android.exoplayer2.util.Util.getPcmEncoding; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.Id3Peeker; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder; -import org.telegram.messenger.exoplayer2.util.FlacStreamInfo; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.BinarySearchSeeker; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.Id3Peeker; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder; +import com.google.android.exoplayer2.util.FlacStreamInfo; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -46,24 +47,14 @@ import java.util.Arrays; */ public final class FlacExtractor implements Extractor { - /** - * Factory that returns one extractor which is a {@link FlacExtractor}. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new FlacExtractor()}; - } - - }; + /** Factory that returns one extractor which is a {@link FlacExtractor}. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new FlacExtractor()}; /** Flags controlling the behavior of the extractor. */ @Retention(RetentionPolicy.SOURCE) @IntDef( - flag = true, - value = {FLAG_DISABLE_ID3_METADATA} - ) + flag = true, + value = {FLAG_DISABLE_ID3_METADATA}) public @interface Flags {} /** @@ -88,6 +79,7 @@ public final class FlacExtractor implements Extractor { private ParsableByteArray outputBuffer; private ByteBuffer outputByteBuffer; + private BinarySearchSeeker.OutputFrameHolder outputFrameHolder; private FlacStreamInfo streamInfo; private Metadata id3Metadata; @@ -140,7 +132,7 @@ public final class FlacExtractor implements Extractor { decoderJni.setData(input); readPastStreamInfo(input); - if (flacBinarySearchSeeker != null && flacBinarySearchSeeker.hasPendingSeek()) { + if (flacBinarySearchSeeker != null && flacBinarySearchSeeker.isSeeking()) { return handlePendingSeek(input, seekPosition); } @@ -224,6 +216,7 @@ public final class FlacExtractor implements Extractor { outputFormat(streamInfo); outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize()); outputByteBuffer = ByteBuffer.wrap(outputBuffer.data); + outputFrameHolder = new BinarySearchSeeker.OutputFrameHolder(outputByteBuffer); } private FlacStreamInfo decodeStreamInfo(ExtractorInput input) @@ -286,9 +279,10 @@ public final class FlacExtractor implements Extractor { private int handlePendingSeek(ExtractorInput input, PositionHolder seekPosition) throws InterruptedException, IOException { int seekResult = - flacBinarySearchSeeker.handlePendingSeek(input, seekPosition, outputByteBuffer); + flacBinarySearchSeeker.handlePendingSeek(input, seekPosition, outputFrameHolder); + ByteBuffer outputByteBuffer = outputFrameHolder.byteBuffer; if (seekResult == RESULT_CONTINUE && outputByteBuffer.limit() > 0) { - writeLastSampleToOutput(outputByteBuffer.limit(), decoderJni.getLastFrameTimestamp()); + writeLastSampleToOutput(outputByteBuffer.limit(), outputFrameHolder.timeUs); } return seekResult; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java similarity index 55% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java index b28bc36d8..3b6a14f61 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java @@ -13,26 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.ext.flac; + +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; /** - * Thrown when an error occurs decoding metadata. + * Configures and queries the underlying native library. */ -public class MetadataDecoderException extends Exception { +public final class FlacLibrary { - /** - * @param message The detail message for this exception. - */ - public MetadataDecoderException(String message) { - super(message); + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.flac"); } - /** - * @param message The detail message for this exception. - * @param cause The cause of this exception. - */ - public MetadataDecoderException(String message, Throwable cause) { - super(message, cause); - } + private FlacLibrary() {} } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/LibflacAudioRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/LibflacAudioRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java index 9bf6673af..64a04c42d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/LibflacAudioRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.flac; +package com.google.android.exoplayer2.ext.flac; import android.os.Handler; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.AudioProcessor; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.audio.SimpleDecoderAudioRenderer; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.AudioProcessor; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.MimeTypes; /** * Decodes and renders audio using the native Flac decoder. @@ -64,7 +64,8 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer { @Override protected FlacDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto) throws FlacDecoderException { - return new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.initializationData); + return new FlacDecoder( + NUM_BUFFERS, NUM_BUFFERS, format.maxInputSize, format.initializationData); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/LibopusAudioRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/LibopusAudioRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java index 05eec1e66..b762968ae 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/LibopusAudioRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java @@ -13,25 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.opus; +package com.google.android.exoplayer2.ext.opus; import android.os.Handler; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.AudioProcessor; -import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; -import org.telegram.messenger.exoplayer2.audio.SimpleDecoderAudioRenderer; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.AudioProcessor; +import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.MimeTypes; /** * Decodes and renders audio using the native Opus decoder. */ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { + /** The number of input and output buffers. */ private static final int NUM_BUFFERS = 16; - private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6; + /** The default input buffer size. */ + private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6; private OpusDecoder decoder; @@ -87,8 +89,15 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { @Override protected OpusDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto) throws OpusDecoderException { - decoder = new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, - format.initializationData, mediaCrypto); + int initialInputBufferSize = + format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE; + decoder = + new OpusDecoder( + NUM_BUFFERS, + NUM_BUFFERS, + initialInputBufferSize, + format.initializationData, + mediaCrypto); return decoder; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java index 7f4095b31..80f46e0c5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.opus; +package com.google.android.exoplayer2.ext.opus; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.decoder.CryptoInfo; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; -import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer; -import org.telegram.messenger.exoplayer2.drm.DecryptionException; -import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.decoder.CryptoInfo; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.decoder.SimpleDecoder; +import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; +import com.google.android.exoplayer2.drm.DecryptionException; +import com.google.android.exoplayer2.drm.ExoMediaCrypto; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoderException.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoderException.java index 40357e81b..664508683 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoderException.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.opus; +package com.google.android.exoplayer2.ext.opus; -import org.telegram.messenger.exoplayer2.audio.AudioDecoderException; +import com.google.android.exoplayer2.audio.AudioDecoderException; /** * Thrown when an Opus decoder error occurs. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusLibrary.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusLibrary.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java index 8c763cf48..867f2e125 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/opus/OpusLibrary.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ext.opus; +package com.google.android.exoplayer2.ext.opus; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; /** * Configures and queries the underlying native library. diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java new file mode 100755 index 000000000..8002c2871 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor; + +import android.support.annotation.IntDef; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.nio.ByteBuffer; + +/** + * A seeker that supports seeking within a stream by searching for the target frame using binary + * search. + * + *

    This seeker operates on a stream that contains multiple frames (or samples). Each frame is + * associated with some kind of timestamps, such as stream time, or frame indices. Given a target + * seek time, the seeker will find the corresponding target timestamp, and perform a search + * operation within the stream to identify the target frame and return the byte position in the + * stream of the target frame. + */ +public abstract class BinarySearchSeeker { + + /** A seeker that looks for a given timestamp from an input. */ + protected interface TimestampSeeker { + + /** + * Searches for a given timestamp from the input. + * + *

    Given a target timestamp and an input stream, this seeker will try to read up to a range + * of {@code searchRangeBytes} bytes from that input, look for all available timestamps from all + * frames in that range, compare those with the target timestamp, and return one of the {@link + * TimestampSearchResult}. + * + * @param input The {@link ExtractorInput} from which data should be read. + * @param targetTimestamp The target timestamp that we are looking for. + * @param outputFrameHolder If {@link TimestampSearchResult#RESULT_TARGET_TIMESTAMP_FOUND} is + * returned, this holder may be updated to hold the extracted frame that contains the target + * frame/sample associated with the target timestamp. + * @return A {@link TimestampSearchResult}, that includes a {@link TimestampSearchResult#result} + * value, and other necessary info: + *

      + *
    • {@link TimestampSearchResult#RESULT_NO_TIMESTAMP} is returned if there is no + * timestamp in the reading range. + *
    • {@link TimestampSearchResult#RESULT_POSITION_UNDERESTIMATED} is returned if all + * timestamps in the range are smaller than the target timestamp. + *
    • {@link TimestampSearchResult#RESULT_POSITION_OVERESTIMATED} is returned if all + * timestamps in the range are larger than the target timestamp. + *
    • {@link TimestampSearchResult#RESULT_TARGET_TIMESTAMP_FOUND} is returned if this + * seeker can find a timestamp that it deems close enough to the given target. + *
    + * + * @throws IOException If an error occurred reading from the input. + * @throws InterruptedException If the thread was interrupted. + */ + TimestampSearchResult searchForTimestamp( + ExtractorInput input, long targetTimestamp, OutputFrameHolder outputFrameHolder) + throws IOException, InterruptedException; + + /** + * The range of bytes from the current input position from which to search for the target + * timestamp. Uses {@link C#LENGTH_UNSET} to signal that there is no limit for the search range. + * + * @see #searchForTimestamp(ExtractorInput, long, OutputFrameHolder) + */ + int getTimestampSearchBytesRange(); + } + + /** + * Holds a frame extracted from a stream, together with the time stamp of the frame in + * microseconds. + */ + public static final class OutputFrameHolder { + + public long timeUs; + public ByteBuffer byteBuffer; + + /** Constructs an instance, wrapping the given byte buffer. */ + public OutputFrameHolder(ByteBuffer outputByteBuffer) { + this.timeUs = 0; + this.byteBuffer = outputByteBuffer; + } + } + + /** + * A converter that converts seek time in stream time into target timestamp for the {@link + * BinarySearchSeeker}. + */ + protected interface SeekTimestampConverter { + /** + * Converts a seek time in microseconds into target timestamp for the {@link + * BinarySearchSeeker}. + */ + long timeUsToTargetTime(long timeUs); + } + + /** + * When seeking within the source, if the offset is smaller than or equal to this value, the seek + * operation will be performed using a skip operation. Otherwise, the source will be reloaded at + * the new seek position. + */ + private static final long MAX_SKIP_BYTES = 256 * 1024; + + protected final BinarySearchSeekMap seekMap; + protected final TimestampSeeker timestampSeeker; + protected @Nullable SeekOperationParams seekOperationParams; + + private final int minimumSearchRange; + + /** + * Constructs an instance. + * + * @param seekTimestampConverter The {@link SeekTimestampConverter} that converts seek time in + * stream time into target timestamp. + * @param timestampSeeker A {@link TimestampSeeker} that will be used to search for timestamps + * within the stream. + * @param durationUs The duration of the stream in microseconds. + * @param floorTimePosition The minimum timestamp value (inclusive) in the stream. + * @param ceilingTimePosition The minimum timestamp value (exclusive) in the stream. + * @param floorBytePosition The starting position of the frame with minimum timestamp value + * (inclusive) in the stream. + * @param ceilingBytePosition The position after the frame with maximum timestamp value in the + * stream. + * @param approxBytesPerFrame Approximated bytes per frame. + * @param minimumSearchRange The minimum byte range that this binary seeker will operate on. If + * the remaining search range is smaller than this value, the search will stop, and the seeker + * will return the position at the floor of the range as the result. + */ + @SuppressWarnings("initialization") + protected BinarySearchSeeker( + SeekTimestampConverter seekTimestampConverter, + TimestampSeeker timestampSeeker, + long durationUs, + long floorTimePosition, + long ceilingTimePosition, + long floorBytePosition, + long ceilingBytePosition, + long approxBytesPerFrame, + int minimumSearchRange) { + this.timestampSeeker = timestampSeeker; + this.minimumSearchRange = minimumSearchRange; + this.seekMap = + new BinarySearchSeekMap( + seekTimestampConverter, + durationUs, + floorTimePosition, + ceilingTimePosition, + floorBytePosition, + ceilingBytePosition, + approxBytesPerFrame); + } + + /** Returns the seek map for the stream. */ + public final SeekMap getSeekMap() { + return seekMap; + } + + /** + * Sets the target time in microseconds within the stream to seek to. + * + * @param timeUs The target time in microseconds within the stream. + */ + public final void setSeekTargetUs(long timeUs) { + if (seekOperationParams != null && seekOperationParams.getSeekTimeUs() == timeUs) { + return; + } + seekOperationParams = createSeekParamsForTargetTimeUs(timeUs); + } + + /** Returns whether the last operation set by {@link #setSeekTargetUs(long)} is still pending. */ + public final boolean isSeeking() { + return seekOperationParams != null; + } + + /** + * Continues to handle the pending seek operation. Returns one of the {@code RESULT_} values from + * {@link Extractor}. + * + * @param input The {@link ExtractorInput} from which data should be read. + * @param seekPositionHolder If {@link Extractor#RESULT_SEEK} is returned, this holder is updated + * to hold the position of the required seek. + * @param outputFrameHolder If {@link Extractor#RESULT_CONTINUE} is returned, this holder may be + * updated to hold the extracted frame that contains the target sample. The caller needs to + * check the byte buffer limit to see if an extracted frame is available. + * @return One of the {@code RESULT_} values defined in {@link Extractor}. + * @throws IOException If an error occurred reading from the input. + * @throws InterruptedException If the thread was interrupted. + */ + public int handlePendingSeek( + ExtractorInput input, PositionHolder seekPositionHolder, OutputFrameHolder outputFrameHolder) + throws InterruptedException, IOException { + TimestampSeeker timestampSeeker = Assertions.checkNotNull(this.timestampSeeker); + while (true) { + SeekOperationParams seekOperationParams = Assertions.checkNotNull(this.seekOperationParams); + long floorPosition = seekOperationParams.getFloorBytePosition(); + long ceilingPosition = seekOperationParams.getCeilingBytePosition(); + long searchPosition = seekOperationParams.getNextSearchBytePosition(); + + if (ceilingPosition - floorPosition <= minimumSearchRange) { + // The seeking range is too small, so we can just continue from the floor position. + markSeekOperationFinished(/* foundTargetFrame= */ false, floorPosition); + return seekToPosition(input, floorPosition, seekPositionHolder); + } + if (!skipInputUntilPosition(input, searchPosition)) { + return seekToPosition(input, searchPosition, seekPositionHolder); + } + + input.resetPeekPosition(); + TimestampSearchResult timestampSearchResult = + timestampSeeker.searchForTimestamp( + input, seekOperationParams.getTargetTimePosition(), outputFrameHolder); + + switch (timestampSearchResult.result) { + case TimestampSearchResult.RESULT_POSITION_OVERESTIMATED: + seekOperationParams.updateSeekCeiling( + timestampSearchResult.timestampToUpdate, timestampSearchResult.bytePositionToUpdate); + break; + case TimestampSearchResult.RESULT_POSITION_UNDERESTIMATED: + seekOperationParams.updateSeekFloor( + timestampSearchResult.timestampToUpdate, timestampSearchResult.bytePositionToUpdate); + break; + case TimestampSearchResult.RESULT_TARGET_TIMESTAMP_FOUND: + markSeekOperationFinished( + /* foundTargetFrame= */ true, timestampSearchResult.bytePositionToUpdate); + skipInputUntilPosition(input, timestampSearchResult.bytePositionToUpdate); + return seekToPosition( + input, timestampSearchResult.bytePositionToUpdate, seekPositionHolder); + case TimestampSearchResult.RESULT_NO_TIMESTAMP: + // We can't find any timestamp in the search range from the search position. + // Give up, and just continue reading from the last search position in this case. + markSeekOperationFinished(/* foundTargetFrame= */ false, searchPosition); + return seekToPosition(input, searchPosition, seekPositionHolder); + default: + throw new IllegalStateException("Invalid case"); + } + } + } + + protected SeekOperationParams createSeekParamsForTargetTimeUs(long timeUs) { + return new SeekOperationParams( + timeUs, + seekMap.timeUsToTargetTime(timeUs), + seekMap.floorTimePosition, + seekMap.ceilingTimePosition, + seekMap.floorBytePosition, + seekMap.ceilingBytePosition, + seekMap.approxBytesPerFrame); + } + + protected final void markSeekOperationFinished(boolean foundTargetFrame, long resultPosition) { + seekOperationParams = null; + onSeekOperationFinished(foundTargetFrame, resultPosition); + } + + protected void onSeekOperationFinished(boolean foundTargetFrame, long resultPosition) { + // Do nothing. + } + + protected final boolean skipInputUntilPosition(ExtractorInput input, long position) + throws IOException, InterruptedException { + long bytesToSkip = position - input.getPosition(); + if (bytesToSkip >= 0 && bytesToSkip <= MAX_SKIP_BYTES) { + input.skipFully((int) bytesToSkip); + return true; + } + return false; + } + + protected final int seekToPosition( + ExtractorInput input, long position, PositionHolder seekPositionHolder) { + if (position == input.getPosition()) { + return Extractor.RESULT_CONTINUE; + } else { + seekPositionHolder.position = position; + return Extractor.RESULT_SEEK; + } + } + + /** + * Contains parameters for a pending seek operation by {@link BinarySearchSeeker}. + * + *

    This class holds parameters for a binary-search for the {@code targetTimePosition} in the + * range [floorPosition, ceilingPosition). + */ + protected static class SeekOperationParams { + private final long seekTimeUs; + private final long targetTimePosition; + private final long approxBytesPerFrame; + + private long floorTimePosition; + private long ceilingTimePosition; + private long floorBytePosition; + private long ceilingBytePosition; + private long nextSearchBytePosition; + + /** + * Returns the next position in the stream to search for target frame, given [floorBytePosition, + * ceilingBytePosition), with corresponding [floorTimePosition, ceilingTimePosition). + */ + protected static long calculateNextSearchBytePosition( + long targetTimePosition, + long floorTimePosition, + long ceilingTimePosition, + long floorBytePosition, + long ceilingBytePosition, + long approxBytesPerFrame) { + if (floorBytePosition + 1 >= ceilingBytePosition + || floorTimePosition + 1 >= ceilingTimePosition) { + return floorBytePosition; + } + long seekTimeDuration = targetTimePosition - floorTimePosition; + float estimatedBytesPerTimeUnit = + (float) (ceilingBytePosition - floorBytePosition) + / (ceilingTimePosition - floorTimePosition); + // It's better to under-estimate rather than over-estimate, because the extractor + // input can skip forward easily, but cannot rewind easily (it may require a new connection + // to be made). + // Therefore, we should reduce the estimated position by some amount, so it will converge to + // the correct frame earlier. + long bytesToSkip = (long) (seekTimeDuration * estimatedBytesPerTimeUnit); + long confidenceInterval = bytesToSkip / 20; + long estimatedFramePosition = floorBytePosition + bytesToSkip - approxBytesPerFrame; + long estimatedPosition = estimatedFramePosition - confidenceInterval; + return Util.constrainValue(estimatedPosition, floorBytePosition, ceilingBytePosition - 1); + } + + protected SeekOperationParams( + long seekTimeUs, + long targetTimePosition, + long floorTimePosition, + long ceilingTimePosition, + long floorBytePosition, + long ceilingBytePosition, + long approxBytesPerFrame) { + this.seekTimeUs = seekTimeUs; + this.targetTimePosition = targetTimePosition; + this.floorTimePosition = floorTimePosition; + this.ceilingTimePosition = ceilingTimePosition; + this.floorBytePosition = floorBytePosition; + this.ceilingBytePosition = ceilingBytePosition; + this.approxBytesPerFrame = approxBytesPerFrame; + this.nextSearchBytePosition = + calculateNextSearchBytePosition( + targetTimePosition, + floorTimePosition, + ceilingTimePosition, + floorBytePosition, + ceilingBytePosition, + approxBytesPerFrame); + } + + /** + * Returns the floor byte position of the range [floorPosition, ceilingPosition) for this seek + * operation. + */ + private long getFloorBytePosition() { + return floorBytePosition; + } + + /** + * Returns the ceiling byte position of the range [floorPosition, ceilingPosition) for this seek + * operation. + */ + private long getCeilingBytePosition() { + return ceilingBytePosition; + } + + /** Returns the target timestamp as translated from the seek time. */ + private long getTargetTimePosition() { + return targetTimePosition; + } + + /** Returns the target seek time in microseconds. */ + private long getSeekTimeUs() { + return seekTimeUs; + } + + /** Updates the floor constraints (inclusive) of the seek operation. */ + private void updateSeekFloor(long floorTimePosition, long floorBytePosition) { + this.floorTimePosition = floorTimePosition; + this.floorBytePosition = floorBytePosition; + updateNextSearchBytePosition(); + } + + /** Updates the ceiling constraints (exclusive) of the seek operation. */ + private void updateSeekCeiling(long ceilingTimePosition, long ceilingBytePosition) { + this.ceilingTimePosition = ceilingTimePosition; + this.ceilingBytePosition = ceilingBytePosition; + updateNextSearchBytePosition(); + } + + /** Returns the next position in the stream to search. */ + private long getNextSearchBytePosition() { + return nextSearchBytePosition; + } + + private void updateNextSearchBytePosition() { + this.nextSearchBytePosition = + calculateNextSearchBytePosition( + targetTimePosition, + floorTimePosition, + ceilingTimePosition, + floorBytePosition, + ceilingBytePosition, + approxBytesPerFrame); + } + } + + /** + * Represents possible search results for {@link + * TimestampSeeker#searchForTimestamp(ExtractorInput, long, OutputFrameHolder)}. + */ + public static final class TimestampSearchResult { + + public static final int RESULT_TARGET_TIMESTAMP_FOUND = 0; + public static final int RESULT_POSITION_OVERESTIMATED = -1; + public static final int RESULT_POSITION_UNDERESTIMATED = -2; + public static final int RESULT_NO_TIMESTAMP = -3; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + RESULT_TARGET_TIMESTAMP_FOUND, + RESULT_POSITION_OVERESTIMATED, + RESULT_POSITION_UNDERESTIMATED, + RESULT_NO_TIMESTAMP + }) + @interface SearchResult {} + + public static final TimestampSearchResult NO_TIMESTAMP_IN_RANGE_RESULT = + new TimestampSearchResult(RESULT_NO_TIMESTAMP, C.TIME_UNSET, C.POSITION_UNSET); + + /** @see TimestampSeeker */ + private final @SearchResult int result; + + /** + * When {@code result} is {@link #RESULT_POSITION_OVERESTIMATED}, the {@link + * SeekOperationParams#ceilingTimePosition} should be updated with this value. When {@code + * result} is {@link #RESULT_POSITION_UNDERESTIMATED}, the {@link + * SeekOperationParams#floorTimePosition} should be updated with this value. + */ + private final long timestampToUpdate; + /** + * When {@code result} is {@link #RESULT_POSITION_OVERESTIMATED}, the {@link + * SeekOperationParams#ceilingBytePosition} should be updated with this value. When {@code + * result} is {@link #RESULT_POSITION_UNDERESTIMATED}, the {@link + * SeekOperationParams#floorBytePosition} should be updated with this value. + */ + private final long bytePositionToUpdate; + + private TimestampSearchResult( + @SearchResult int result, long timestampToUpdate, long bytePositionToUpdate) { + this.result = result; + this.timestampToUpdate = timestampToUpdate; + this.bytePositionToUpdate = bytePositionToUpdate; + } + + /** + * Returns a result to signal that the current position in the input stream overestimates the + * true position of the target frame, and the {@link BinarySearchSeeker} should modify its + * {@link SeekOperationParams}'s ceiling timestamp and byte position using the given values. + */ + public static TimestampSearchResult overestimatedResult( + long newCeilingTimestamp, long newCeilingBytePosition) { + return new TimestampSearchResult( + RESULT_POSITION_OVERESTIMATED, newCeilingTimestamp, newCeilingBytePosition); + } + + /** + * Returns a result to signal that the current position in the input stream underestimates the + * true position of the target frame, and the {@link BinarySearchSeeker} should modify its + * {@link SeekOperationParams}'s floor timestamp and byte position using the given values. + */ + public static TimestampSearchResult underestimatedResult( + long newFloorTimestamp, long newCeilingBytePosition) { + return new TimestampSearchResult( + RESULT_POSITION_UNDERESTIMATED, newFloorTimestamp, newCeilingBytePosition); + } + + /** + * Returns a result to signal that the target timestamp has been found at the {@code + * resultBytePosition}, and the seek operation can stop. + * + *

    Note that when this value is returned from {@link + * TimestampSeeker#searchForTimestamp(ExtractorInput, long, OutputFrameHolder)}, the {@link + * OutputFrameHolder} may be updated to hold the target frame as an optimization. + */ + public static TimestampSearchResult targetFoundResult(long resultBytePosition) { + return new TimestampSearchResult( + RESULT_TARGET_TIMESTAMP_FOUND, C.TIME_UNSET, resultBytePosition); + } + } + + /** + * A {@link SeekMap} implementation that returns the estimated byte location from {@link + * SeekOperationParams#calculateNextSearchBytePosition(long, long, long, long, long, long)} for + * each {@link #getSeekPoints(long)} query. + */ + public static class BinarySearchSeekMap implements SeekMap { + private final SeekTimestampConverter seekTimestampConverter; + private final long durationUs; + private final long floorTimePosition; + private final long ceilingTimePosition; + private final long floorBytePosition; + private final long ceilingBytePosition; + private final long approxBytesPerFrame; + + /** Constructs a new instance of this seek map. */ + public BinarySearchSeekMap( + SeekTimestampConverter seekTimestampConverter, + long durationUs, + long floorTimePosition, + long ceilingTimePosition, + long floorBytePosition, + long ceilingBytePosition, + long approxBytesPerFrame) { + this.seekTimestampConverter = seekTimestampConverter; + this.durationUs = durationUs; + this.floorTimePosition = floorTimePosition; + this.ceilingTimePosition = ceilingTimePosition; + this.floorBytePosition = floorBytePosition; + this.ceilingBytePosition = ceilingBytePosition; + this.approxBytesPerFrame = approxBytesPerFrame; + } + + @Override + public boolean isSeekable() { + return true; + } + + @Override + public SeekPoints getSeekPoints(long timeUs) { + long nextSearchPosition = + SeekOperationParams.calculateNextSearchBytePosition( + /* targetTimePosition= */ seekTimestampConverter.timeUsToTargetTime(timeUs), + /* floorTimePosition= */ floorTimePosition, + /* ceilingTimePosition= */ ceilingTimePosition, + /* floorBytePosition= */ floorBytePosition, + /* ceilingBytePosition= */ ceilingBytePosition, + /* approxBytesPerFrame= */ approxBytesPerFrame); + return new SeekPoints(new SeekPoint(timeUs, nextSearchPosition)); + } + + @Override + public long getDurationUs() { + return durationUs; + } + + /** @see SeekTimestampConverter#timeUsToTargetTime(long) */ + public long timeUsToTargetTime(long timeUs) { + return seekTimestampConverter.timeUsToTargetTime(timeUs); + } + } + + /** + * A {@link SeekTimestampConverter} implementation that returns the seek time itself as the + * timestamp for a seek time position. + */ + private static final class DefaultSeekTimestampConverter implements SeekTimestampConverter { + + @Override + public long timeUsToTargetTime(long timeUs) { + return timeUs; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ChunkIndex.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ChunkIndex.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ChunkIndex.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ChunkIndex.java index 9476a012d..7ddd03bbd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ChunkIndex.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ChunkIndex.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ConstantBitrateSeekMap.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ConstantBitrateSeekMap.java new file mode 100755 index 000000000..abce01b5e --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ConstantBitrateSeekMap.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; + +/** + * A {@link SeekMap} implementation that assumes the stream has a constant bitrate and consists of + * multiple independent frames of the same size. Seek points are calculated to be at frame + * boundaries. + */ +public class ConstantBitrateSeekMap implements SeekMap { + + private final long inputLength; + private final long firstFrameBytePosition; + private final int frameSize; + private final long dataSize; + private final int bitrate; + private final long durationUs; + + /** + * Constructs a new instance from a stream. + * + * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown. + * @param firstFrameBytePosition The byte-position of the first frame in the stream. + * @param bitrate The bitrate (which is assumed to be constant in the stream). + * @param frameSize The size of each frame in the stream in bytes. May be {@link C#LENGTH_UNSET} + * if unknown. + */ + public ConstantBitrateSeekMap( + long inputLength, long firstFrameBytePosition, int bitrate, int frameSize) { + this.inputLength = inputLength; + this.firstFrameBytePosition = firstFrameBytePosition; + this.frameSize = frameSize == C.LENGTH_UNSET ? 1 : frameSize; + this.bitrate = bitrate; + + if (inputLength == C.LENGTH_UNSET) { + dataSize = C.LENGTH_UNSET; + durationUs = C.TIME_UNSET; + } else { + dataSize = inputLength - firstFrameBytePosition; + durationUs = getTimeUsAtPosition(inputLength, firstFrameBytePosition, bitrate); + } + } + + @Override + public boolean isSeekable() { + return dataSize != C.LENGTH_UNSET; + } + + @Override + public SeekPoints getSeekPoints(long timeUs) { + if (dataSize == C.LENGTH_UNSET) { + return new SeekPoints(new SeekPoint(0, firstFrameBytePosition)); + } + long seekFramePosition = getFramePositionForTimeUs(timeUs); + long seekTimeUs = getTimeUsAtPosition(seekFramePosition); + SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekFramePosition); + if (seekTimeUs >= timeUs || seekFramePosition + frameSize >= inputLength) { + return new SeekPoints(seekPoint); + } else { + long secondSeekPosition = seekFramePosition + frameSize; + long secondSeekTimeUs = getTimeUsAtPosition(secondSeekPosition); + SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition); + return new SeekPoints(seekPoint, secondSeekPoint); + } + } + + @Override + public long getDurationUs() { + return durationUs; + } + + /** + * Returns the stream time in microseconds for a given position. + * + * @param position The stream byte-position. + * @return The stream time in microseconds for the given position. + */ + public long getTimeUsAtPosition(long position) { + return getTimeUsAtPosition(position, firstFrameBytePosition, bitrate); + } + + // Internal methods + + /** + * Returns the stream time in microseconds for a given stream position. + * + * @param position The stream byte-position. + * @param firstFrameBytePosition The position of the first frame in the stream. + * @param bitrate The bitrate (which is assumed to be constant in the stream). + * @return The stream time in microseconds for the given stream position. + */ + private static long getTimeUsAtPosition(long position, long firstFrameBytePosition, int bitrate) { + return Math.max(0, position - firstFrameBytePosition) + * C.BITS_PER_BYTE + * C.MICROS_PER_SECOND + / bitrate; + } + + private long getFramePositionForTimeUs(long timeUs) { + long positionOffset = (timeUs * bitrate) / (C.MICROS_PER_SECOND * C.BITS_PER_BYTE); + // Constrain to nearest preceding frame offset. + positionOffset = (positionOffset / frameSize) * frameSize; + positionOffset = + Util.constrainValue(positionOffset, /* min= */ 0, /* max= */ dataSize - frameSize); + return firstFrameBytePosition + positionOffset; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorInput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorInput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java index 5f63ec85b..c3f630409 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorInput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorsFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorsFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java index 75a715b8c..425f2b77c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DefaultExtractorsFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java @@ -13,23 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.extractor.amr.AmrExtractor; -import org.telegram.messenger.exoplayer2.extractor.flv.FlvExtractor; -import org.telegram.messenger.exoplayer2.extractor.mkv.MatroskaExtractor; -import org.telegram.messenger.exoplayer2.extractor.mp3.Mp3Extractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.Mp4Extractor; -import org.telegram.messenger.exoplayer2.extractor.ogg.OggExtractor; -import org.telegram.messenger.exoplayer2.extractor.ts.Ac3Extractor; -import org.telegram.messenger.exoplayer2.extractor.ts.AdtsExtractor; -import org.telegram.messenger.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; -import org.telegram.messenger.exoplayer2.extractor.ts.PsExtractor; -import org.telegram.messenger.exoplayer2.extractor.ts.TsExtractor; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader; -import org.telegram.messenger.exoplayer2.extractor.wav.WavExtractor; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.extractor.amr.AmrExtractor; +import com.google.android.exoplayer2.extractor.flv.FlvExtractor; +import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; +import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor; +import com.google.android.exoplayer2.extractor.ogg.OggExtractor; +import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; +import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; +import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; +import com.google.android.exoplayer2.extractor.ts.PsExtractor; +import com.google.android.exoplayer2.extractor.ts.TsExtractor; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader; +import com.google.android.exoplayer2.extractor.wav.WavExtractor; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.lang.reflect.Constructor; /** @@ -59,7 +59,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { try { // LINT.IfChange flacExtractorConstructor = - Class.forName("org.telegram.messenger.exoplayer2.ext.flac.FlacExtractor") + Class.forName("com.google.android.exoplayer2.ext.flac.FlacExtractor") .asSubclass(Extractor.class) .getConstructor(); // LINT.ThenChange(../../../../../../../../proguard-rules.txt) diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DummyTrackOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DummyTrackOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java index 587af494b..9eaf0f7ef 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/DummyTrackOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; @@ -50,9 +51,12 @@ public final class DummyTrackOutput implements TrackOutput { } @Override - public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData cryptoData) { + public void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData cryptoData) { // Do nothing. } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Extractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Extractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java index ae7c986e5..c63aad541 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Extractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.C; +import android.support.annotation.IntDef; +import com.google.android.exoplayer2.C; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Extracts media data from a container format. @@ -41,6 +44,11 @@ public interface Extractor { */ int RESULT_END_OF_INPUT = C.RESULT_END_OF_INPUT; + /** Result values that can be returned by {@link #read(ExtractorInput, PositionHolder)}. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {RESULT_CONTINUE, RESULT_SEEK, RESULT_END_OF_INPUT}) + @interface ReadResult {} + /** * Returns whether this extractor can extract samples from the {@link ExtractorInput}, which must * provide data from the start of the stream. @@ -63,14 +71,14 @@ public interface Extractor { void init(ExtractorOutput output); /** - * Extracts data read from a provided {@link ExtractorInput}. Must not be called before - * {@link #init(ExtractorOutput)}. - *

    - * A single call to this method will block until some progress has been made, but will not block - * for longer than this. Hence each call will consume only a small amount of input data. - *

    - * In the common case, {@link #RESULT_CONTINUE} is returned to indicate that the - * {@link ExtractorInput} passed to the next read is required to provide data continuing from the + * Extracts data read from a provided {@link ExtractorInput}. Must not be called before {@link + * #init(ExtractorOutput)}. + * + *

    A single call to this method will block until some progress has been made, but will not + * block for longer than this. Hence each call will consume only a small amount of input data. + * + *

    In the common case, {@link #RESULT_CONTINUE} is returned to indicate that the {@link + * ExtractorInput} passed to the next read is required to provide data continuing from the * position in the stream reached by the returning call. If the extractor requires data to be * provided from a different position, then that position is set in {@code seekPosition} and * {@link #RESULT_SEEK} is returned. If the extractor reached the end of the data provided by the @@ -83,6 +91,7 @@ public interface Extractor { * @throws IOException If an error occurred reading from the input. * @throws InterruptedException If the thread was interrupted. */ + @ReadResult int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorInput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorInput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java index da7b20317..45650c45f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorInput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorOutput.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorOutput.java index c266fa239..a59cb1d1f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorOutput.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; /** * Receives stream level data extracted by an {@link Extractor}. @@ -26,7 +26,7 @@ public interface ExtractorOutput { * The same {@link TrackOutput} is returned if multiple calls are made with the same {@code id}. * * @param id A track identifier. - * @param type The type of the track. Typically one of the {@link org.telegram.messenger.exoplayer2.C} + * @param type The type of the track. Typically one of the {@link com.google.android.exoplayer2.C} * {@code TRACK_TYPE_*} constants. * @return The {@link TrackOutput} for the given track identifier. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorsFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorsFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java index a047617a7..b89990ff1 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ExtractorsFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; /** * Factory for arrays of {@link Extractor}s. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/GaplessInfoHolder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/GaplessInfoHolder.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/GaplessInfoHolder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/GaplessInfoHolder.java index 7a0fa45b7..54d48350f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/GaplessInfoHolder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/GaplessInfoHolder.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.CommentFrame; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder.FramePredicate; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.CommentFrame; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate; +import com.google.android.exoplayer2.metadata.id3.InternalFrame; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -39,7 +40,8 @@ public final class GaplessInfoHolder { } }; - private static final String GAPLESS_COMMENT_ID = "iTunSMPB"; + private static final String GAPLESS_DOMAIN = "com.apple.iTunes"; + private static final String GAPLESS_DESCRIPTION = "iTunSMPB"; private static final Pattern GAPLESS_COMMENT_PATTERN = Pattern.compile("^ [0-9a-fA-F]{8} ([0-9a-fA-F]{8}) ([0-9a-fA-F]{8})"); @@ -91,7 +93,15 @@ public final class GaplessInfoHolder { Metadata.Entry entry = metadata.get(i); if (entry instanceof CommentFrame) { CommentFrame commentFrame = (CommentFrame) entry; - if (setFromComment(commentFrame.description, commentFrame.text)) { + if (GAPLESS_DESCRIPTION.equals(commentFrame.description) + && setFromComment(commentFrame.text)) { + return true; + } + } else if (entry instanceof InternalFrame) { + InternalFrame internalFrame = (InternalFrame) entry; + if (GAPLESS_DOMAIN.equals(internalFrame.domain) + && GAPLESS_DESCRIPTION.equals(internalFrame.description) + && setFromComment(internalFrame.text)) { return true; } } @@ -103,14 +113,10 @@ public final class GaplessInfoHolder { * Populates the holder with data parsed from a gapless playback comment (stored in an ID3 header * or MPEG 4 user data), if valid and non-zero. * - * @param name The comment's identifier. * @param data The comment's payload data. * @return Whether the holder was populated. */ - private boolean setFromComment(String name, String data) { - if (!GAPLESS_COMMENT_ID.equals(name)) { - return false; - } + private boolean setFromComment(String data) { Matcher matcher = GAPLESS_COMMENT_PATTERN.matcher(data); if (matcher.find()) { try { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Id3Peeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Id3Peeker.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Id3Peeker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Id3Peeker.java index 06097de60..8dbcfafaf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/Id3Peeker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/Id3Peeker.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/MpegAudioHeader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/MpegAudioHeader.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/MpegAudioHeader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/MpegAudioHeader.java index 146071b57..f394a7415 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/MpegAudioHeader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/MpegAudioHeader.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.MimeTypes; /** * An MPEG audio frame header. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/PositionHolder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/PositionHolder.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/PositionHolder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/PositionHolder.java index 89473c1d5..d1f5d7646 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/PositionHolder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/PositionHolder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; /** * Holds a position in the stream. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekMap.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekMap.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java index 9d12a8164..b7aaa2a31 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekMap.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; /** * Maps seek positions (in microseconds) to corresponding positions (byte offsets) in the stream. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekPoint.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekPoint.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekPoint.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekPoint.java index 3a5af3097..8b920bc02 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/SeekPoint.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/SeekPoint.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; import android.support.annotation.Nullable; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/TrackOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/TrackOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java index cd3ad71e8..7b832eb40 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/TrackOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor; +package com.google.android.exoplayer2.extractor; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; import java.util.Arrays; @@ -125,21 +125,23 @@ public interface TrackOutput { /** * Called when metadata associated with a sample has been extracted from the stream. - *

    - * The corresponding sample data will have already been passed to the output via calls to - * {@link #sampleData(ExtractorInput, int, boolean)} or - * {@link #sampleData(ParsableByteArray, int)}. + * + *

    The corresponding sample data will have already been passed to the output via calls to + * {@link #sampleData(ExtractorInput, int, boolean)} or {@link #sampleData(ParsableByteArray, + * int)}. * * @param timeUs The media timestamp associated with the sample, in microseconds. * @param flags Flags associated with the sample. See {@code C.BUFFER_FLAG_*}. * @param size The size of the sample data, in bytes. - * @param offset The number of bytes that have been passed to - * {@link #sampleData(ExtractorInput, int, boolean)} or - * {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample - * whose metadata is being passed. + * @param offset The number of bytes that have been passed to {@link #sampleData(ExtractorInput, + * int, boolean)} or {@link #sampleData(ParsableByteArray, int)} since the last byte belonging + * to the sample whose metadata is being passed. * @param encryptionData The encryption data required to decrypt the sample. May be null. */ - void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData encryptionData); - + void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData encryptionData); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/amr/AmrExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java similarity index 63% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/amr/AmrExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java index 6382fd63c..194a711b6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/amr/AmrExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java @@ -13,22 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.amr; +package com.google.android.exoplayer2.extractor.amr; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.IntDef; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ConstantBitrateSeekMap; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** @@ -49,6 +54,18 @@ public final class AmrExtractor implements Extractor { } }; + /** Flags controlling the behavior of the extractor. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + flag = true, + value = {FLAG_ENABLE_CONSTANT_BITRATE_SEEKING}) + public @interface Flags {} + /** + * Flag to force enable seeking using a constant bitrate assumption in cases where seeking would + * otherwise not be possible. + */ + public static final int FLAG_ENABLE_CONSTANT_BITRATE_SEEKING = 1; + /** * The frame size in bytes, including header (1 byte), for each of the 16 frame types for AMR * narrow band. @@ -100,23 +117,43 @@ public final class AmrExtractor implements Extractor { /** Theoretical maximum frame size for a AMR frame. */ private static final int MAX_FRAME_SIZE_BYTES = frameSizeBytesByTypeWb[8]; + /** + * The required number of samples in the stream with same sample size to classify the stream as a + * constant-bitrate-stream. + */ + private static final int NUM_SAME_SIZE_CONSTANT_BIT_RATE_THRESHOLD = 20; private static final int SAMPLE_RATE_WB = 16_000; private static final int SAMPLE_RATE_NB = 8_000; private static final int SAMPLE_TIME_PER_FRAME_US = 20_000; private final byte[] scratch; + private final @Flags int flags; private boolean isWideBand; private long currentSampleTimeUs; - private int currentSampleTotalBytes; + private int currentSampleSize; private int currentSampleBytesRemaining; + private boolean hasOutputSeekMap; + private long firstSamplePosition; + private int firstSampleSize; + private int numSamplesWithSameSize; + private long timeOffsetUs; + private ExtractorOutput extractorOutput; private TrackOutput trackOutput; + private @Nullable SeekMap seekMap; private boolean hasOutputFormat; public AmrExtractor() { + this(/* flags= */ 0); + } + + /** @param flags Flags that control the extractor's behavior. */ + public AmrExtractor(@Flags int flags) { + this.flags = flags; scratch = new byte[1]; + firstSampleSize = C.LENGTH_UNSET; } // Extractor implementation. @@ -127,10 +164,10 @@ public final class AmrExtractor implements Extractor { } @Override - public void init(ExtractorOutput output) { - output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); - trackOutput = output.track(/* id= */ 0, C.TRACK_TYPE_AUDIO); - output.endTracks(); + public void init(ExtractorOutput extractorOutput) { + this.extractorOutput = extractorOutput; + trackOutput = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_AUDIO); + extractorOutput.endTracks(); } @Override @@ -142,14 +179,21 @@ public final class AmrExtractor implements Extractor { } } maybeOutputFormat(); - return readSample(input); + int sampleReadResult = readSample(input); + maybeOutputSeekMap(input.getLength(), sampleReadResult); + return sampleReadResult; } @Override public void seek(long position, long timeUs) { currentSampleTimeUs = 0; - currentSampleTotalBytes = 0; + currentSampleSize = 0; currentSampleBytesRemaining = 0; + if (position != 0 && seekMap instanceof ConstantBitrateSeekMap) { + timeOffsetUs = ((ConstantBitrateSeekMap) seekMap).getTimeUsAtPosition(position); + } else { + timeOffsetUs = 0; + } } @Override @@ -228,11 +272,18 @@ public final class AmrExtractor implements Extractor { private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException { if (currentSampleBytesRemaining == 0) { try { - currentSampleTotalBytes = readNextSampleSize(extractorInput); + currentSampleSize = peekNextSampleSize(extractorInput); } catch (EOFException e) { return RESULT_END_OF_INPUT; } - currentSampleBytesRemaining = currentSampleTotalBytes; + currentSampleBytesRemaining = currentSampleSize; + if (firstSampleSize == C.LENGTH_UNSET) { + firstSamplePosition = extractorInput.getPosition(); + firstSampleSize = currentSampleSize; + } + if (firstSampleSize == currentSampleSize) { + numSamplesWithSameSize++; + } } int bytesAppended = @@ -247,16 +298,16 @@ public final class AmrExtractor implements Extractor { } trackOutput.sampleMetadata( - currentSampleTimeUs, + timeOffsetUs + currentSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, - currentSampleTotalBytes, + currentSampleSize, /* offset= */ 0, /* encryptionData= */ null); currentSampleTimeUs += SAMPLE_TIME_PER_FRAME_US; return RESULT_CONTINUE; } - private int readNextSampleSize(ExtractorInput extractorInput) + private int peekNextSampleSize(ExtractorInput extractorInput) throws IOException, InterruptedException { extractorInput.resetPeekPosition(); extractorInput.peekFully(scratch, /* offset= */ 0, /* length= */ 1); @@ -296,4 +347,39 @@ public final class AmrExtractor implements Extractor { // For narrow band, type 12-14 are for future use. return !isWideBand && (frameType < 12 || frameType > 14); } + + private void maybeOutputSeekMap(long inputLength, int sampleReadResult) { + if (hasOutputSeekMap) { + return; + } + + if ((flags & FLAG_ENABLE_CONSTANT_BITRATE_SEEKING) == 0 + || inputLength == C.LENGTH_UNSET + || (firstSampleSize != C.LENGTH_UNSET && firstSampleSize != currentSampleSize)) { + seekMap = new SeekMap.Unseekable(C.TIME_UNSET); + extractorOutput.seekMap(seekMap); + hasOutputSeekMap = true; + } else if (numSamplesWithSameSize >= NUM_SAME_SIZE_CONSTANT_BIT_RATE_THRESHOLD + || sampleReadResult == RESULT_END_OF_INPUT) { + seekMap = getConstantBitrateSeekMap(inputLength); + extractorOutput.seekMap(seekMap); + hasOutputSeekMap = true; + } + } + + private SeekMap getConstantBitrateSeekMap(long inputLength) { + int bitrate = getBitrateFromFrameSize(firstSampleSize, SAMPLE_TIME_PER_FRAME_US); + return new ConstantBitrateSeekMap(inputLength, firstSamplePosition, bitrate, firstSampleSize); + } + + /** + * Returns the stream bitrate, given a frame size and the duration of that frame in microseconds. + * + * @param frameSize The size of each frame in the stream. + * @param durationUsPerFrame The duration of the given frame in microseconds. + * @return The stream bitrate. + */ + private static int getBitrateFromFrameSize(int frameSize, long durationUsPerFrame) { + return (int) ((frameSize * C.BITS_PER_BYTE * C.MICROS_PER_SECOND) / durationUsPerFrame); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/AudioTagPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/AudioTagPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java index a16ed06da..ec5ad88ae 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/AudioTagPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.flv; +package com.google.android.exoplayer2.extractor.flv; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Collections; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/FlvExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/FlvExtractor.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/FlvExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/FlvExtractor.java index 72bc1feaa..604a52052 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/FlvExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/FlvExtractor.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.flv; +package com.google.android.exoplayer2.extractor.flv; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -34,17 +34,8 @@ import java.lang.annotation.RetentionPolicy; */ public final class FlvExtractor implements Extractor { - /** - * Factory for {@link FlvExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new FlvExtractor()}; - } - - }; + /** Factory for {@link FlvExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new FlvExtractor()}; /** * Extractor states. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/ScriptTagPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/ScriptTagPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java index e7f2f0d27..2dec85ffc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/ScriptTagPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.flv; +package com.google.android.exoplayer2.extractor.flv; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/TagPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/TagPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java index 98dca6e49..e8652d653 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/TagPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.flv; +package com.google.android.exoplayer2.extractor.flv; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Extracts individual samples from FLV tags, preserving original order. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/VideoTagPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/VideoTagPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java index d9af2a534..92db91e20 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/flv/VideoTagPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.flv; +package com.google.android.exoplayer2.extractor.flv; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.video.AvcConfig; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.video.AvcConfig; /** * Parses video tags from an FLV stream and extracts H.264 nal units. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/DefaultEbmlReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/DefaultEbmlReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java index 90e2e746f..c0494e1ee 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/DefaultEbmlReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.Assertions; import java.io.EOFException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Stack; +import java.util.ArrayDeque; /** * Default implementation of {@link EbmlReader}. @@ -46,15 +46,21 @@ import java.util.Stack; private static final int VALID_FLOAT32_ELEMENT_SIZE_BYTES = 4; private static final int VALID_FLOAT64_ELEMENT_SIZE_BYTES = 8; - private final byte[] scratch = new byte[8]; - private final Stack masterElementsStack = new Stack<>(); - private final VarintReader varintReader = new VarintReader(); + private final byte[] scratch; + private final ArrayDeque masterElementsStack; + private final VarintReader varintReader; private EbmlReaderOutput output; private @ElementState int elementState; private int elementId; private long elementContentSize; + public DefaultEbmlReader() { + scratch = new byte[8]; + masterElementsStack = new ArrayDeque<>(); + varintReader = new VarintReader(); + } + @Override public void init(EbmlReaderOutput eventHandler) { this.output = eventHandler; @@ -100,7 +106,7 @@ import java.util.Stack; case EbmlReaderOutput.TYPE_MASTER: long elementContentPosition = input.getPosition(); long elementEndPosition = elementContentPosition + elementContentSize; - masterElementsStack.add(new MasterElement(elementId, elementEndPosition)); + masterElementsStack.push(new MasterElement(elementId, elementEndPosition)); output.startMasterElement(elementId, elementContentPosition, elementContentSize); elementState = ELEMENT_STATE_READ_ID; return true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReader.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReader.java index 27296ed65..9987b3c8e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReader.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReaderOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReaderOutput.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReaderOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReaderOutput.java index 3bcaaa160..b1cd508c8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/EbmlReaderOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/EbmlReaderOutput.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/MatroskaExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/MatroskaExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index af409c936..5ff52a39d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -13,37 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.audio.Ac3Util; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.LongArray; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.video.AvcConfig; -import org.telegram.messenger.exoplayer2.video.ColorInfo; -import org.telegram.messenger.exoplayer2.video.HevcConfig; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.audio.Ac3Util; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.LongArray; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.AvcConfig; +import com.google.android.exoplayer2.video.ColorInfo; +import com.google.android.exoplayer2.video.HevcConfig; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -61,17 +61,8 @@ import java.util.UUID; */ public final class MatroskaExtractor implements Extractor { - /** - * Factory for {@link MatroskaExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new MatroskaExtractor()}; - } - - }; + /** Factory for {@link MatroskaExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new MatroskaExtractor()}; /** * Flags controlling the behavior of the extractor. @@ -616,10 +607,10 @@ public final class MatroskaExtractor implements Extractor { currentTrack.number = (int) value; break; case ID_FLAG_DEFAULT: - currentTrack.flagForced = value == 1; + currentTrack.flagDefault = value == 1; break; case ID_FLAG_FORCED: - currentTrack.flagDefault = value == 1; + currentTrack.flagForced = value == 1; break; case ID_TRACK_TYPE: currentTrack.type = (int) value; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/Sniffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/Sniffer.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/Sniffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/Sniffer.java index a30db4c94..62c940491 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/Sniffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/Sniffer.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; /** @@ -40,7 +40,7 @@ import java.io.IOException; } /** - * @see org.telegram.messenger.exoplayer2.extractor.Extractor#sniff(ExtractorInput) + * @see com.google.android.exoplayer2.extractor.Extractor#sniff(ExtractorInput) */ public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { long inputLength = input.getLength(); @@ -78,8 +78,9 @@ import java.io.IOException; return false; } if (size != 0) { - input.advancePeekPosition((int) size); - peekLength += size; + int sizeInt = (int) size; + input.advancePeekPosition(sizeInt); + peekLength += sizeInt; } } return peekLength == headerStart + headerSize; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/VarintReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/VarintReader.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/VarintReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/VarintReader.java index 42165f930..a94a5ec21 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mkv/VarintReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mkv/VarintReader.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mkv; +package com.google.android.exoplayer2.extractor.mkv; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorInput; import java.io.EOFException; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java new file mode 100755 index 000000000..bffc43a54 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor.mp3; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ConstantBitrateSeekMap; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; + +/** + * MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate. + */ +/* package */ final class ConstantBitrateSeeker extends ConstantBitrateSeekMap + implements Mp3Extractor.Seeker { + + /** + * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown. + * @param firstFramePosition The position of the first frame in the stream. + * @param mpegAudioHeader The MPEG audio header associated with the first frame. + */ + public ConstantBitrateSeeker( + long inputLength, long firstFramePosition, MpegAudioHeader mpegAudioHeader) { + super(inputLength, firstFramePosition, mpegAudioHeader.bitrate, mpegAudioHeader.frameSize); + } + + @Override + public long getTimeUs(long position) { + return getTimeUsAtPosition(position); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/Mp3Extractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/Mp3Extractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java index 5c211b9f1..73dd0ec21 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/Mp3Extractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java @@ -13,26 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp3; +package com.google.android.exoplayer2.extractor.mp3; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.GaplessInfoHolder; -import org.telegram.messenger.exoplayer2.extractor.Id3Peeker; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.GaplessInfoHolder; +import com.google.android.exoplayer2.extractor.Id3Peeker; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; import java.lang.annotation.Retention; @@ -43,17 +43,8 @@ import java.lang.annotation.RetentionPolicy; */ public final class Mp3Extractor implements Extractor { - /** - * Factory for {@link Mp3Extractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new Mp3Extractor()}; - } - - }; + /** Factory for {@link Mp3Extractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new Mp3Extractor()}; /** * Flags controlling the behavior of the extractor. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/VbriSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/VbriSeeker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java index a2e52d36a..f918b5c43 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/VbriSeeker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp3; +package com.google.android.exoplayer2.extractor.mp3; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; /** * MP3 seeker that uses metadata from a VBRI header. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/XingSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/XingSeeker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java index c279c133f..a3bd5a2da 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/XingSeeker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp3; +package com.google.android.exoplayer2.extractor.mp3; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; /** * MP3 seeker that uses metadata from a Xing header. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Atom.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Atom.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java index 6de850ed9..f59214fc3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Atom.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -214,14 +215,14 @@ import java.util.List; /** * Returns the child leaf of the given type. - *

    - * If no child exists with the given type then null is returned. If multiple children exist with - * the given type then the first one to have been added is returned. + * + *

    If no child exists with the given type then null is returned. If multiple children exist + * with the given type then the first one to have been added is returned. * * @param type The leaf type. * @return The child leaf of the given type, or null if no such child exists. */ - public LeafAtom getLeafAtomOfType(int type) { + public @Nullable LeafAtom getLeafAtomOfType(int type) { int childrenSize = leafChildren.size(); for (int i = 0; i < childrenSize; i++) { LeafAtom atom = leafChildren.get(i); @@ -234,14 +235,14 @@ import java.util.List; /** * Returns the child container of the given type. - *

    - * If no child exists with the given type then null is returned. If multiple children exist with - * the given type then the first one to have been added is returned. + * + *

    If no child exists with the given type then null is returned. If multiple children exist + * with the given type then the first one to have been added is returned. * * @param type The container type. * @return The child container of the given type, or null if no such child exists. */ - public ContainerAtom getContainerAtomOfType(int type) { + public @Nullable ContainerAtom getContainerAtomOfType(int type) { int childrenSize = containerChildren.size(); for (int i = 0; i < childrenSize; i++) { ContainerAtom atom = containerChildren.get(i); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/AtomParsers.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/AtomParsers.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index b85d3997a..fe7918569 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/AtomParsers.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -13,26 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import static org.telegram.messenger.exoplayer2.util.MimeTypes.getMimeTypeFromMp4ObjectType; +import static com.google.android.exoplayer2.util.MimeTypes.getMimeTypeFromMp4ObjectType; import android.util.Log; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.audio.Ac3Util; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.extractor.GaplessInfoHolder; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.video.AvcConfig; -import org.telegram.messenger.exoplayer2.video.HevcConfig; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.audio.Ac3Util; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.extractor.GaplessInfoHolder; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.AvcConfig; +import com.google.android.exoplayer2.video.HevcConfig; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -43,6 +43,9 @@ import java.util.List; */ /* package */ final class AtomParsers { + /** Thrown if an edit list couldn't be applied. */ + public static final class UnhandledEditListException extends ParserException {} + private static final String TAG = "AtomParsers"; private static final int TYPE_vide = Util.getIntegerCodeForString("vide"); @@ -117,10 +120,12 @@ import java.util.List; * @param stblAtom stbl (sample table) atom to decode. * @param gaplessInfoHolder Holder to populate with gapless playback information. * @return Sample table described by the stbl atom. - * @throws ParserException If the resulting sample sequence does not contain a sync sample. + * @throws UnhandledEditListException Thrown if the edit list can't be applied. + * @throws ParserException Thrown if the stbl atom can't be parsed. */ - public static TrackSampleTable parseStbl(Track track, Atom.ContainerAtom stblAtom, - GaplessInfoHolder gaplessInfoHolder) throws ParserException { + public static TrackSampleTable parseStbl( + Track track, Atom.ContainerAtom stblAtom, GaplessInfoHolder gaplessInfoHolder) + throws ParserException { SampleSizeBox sampleSizeBox; Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz); if (stszAtom != null) { @@ -136,7 +141,13 @@ import java.util.List; int sampleCount = sampleSizeBox.getSampleCount(); if (sampleCount == 0) { return new TrackSampleTable( - new long[0], new int[0], 0, new long[0], new int[0], C.TIME_UNSET); + track, + /* offsets= */ new long[0], + /* sizes= */ new int[0], + /* maximumSize= */ 0, + /* timestampsUs= */ new long[0], + /* flags= */ new int[0], + /* durationUs= */ C.TIME_UNSET); } // Entries are byte offsets of chunks. @@ -315,7 +326,8 @@ import java.util.List; // There is no edit list, or we are ignoring it as we already have gapless metadata to apply. // This implementation does not support applying both gapless metadata and an edit list. Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale); - return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags, durationUs); + return new TrackSampleTable( + track, offsets, sizes, maximumSize, timestamps, flags, durationUs); } // See the BMFF spec (ISO 14496-12) subsection 8.6.6. Edit lists that require prerolling from a @@ -342,7 +354,8 @@ import java.util.List; gaplessInfoHolder.encoderDelay = (int) encoderDelay; gaplessInfoHolder.encoderPadding = (int) encoderPadding; Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale); - return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags, durationUs); + return new TrackSampleTable( + track, offsets, sizes, maximumSize, timestamps, flags, durationUs); } } } @@ -359,7 +372,8 @@ import java.util.List; } durationUs = Util.scaleLargeTimestamp(duration - editStartTime, C.MICROS_PER_SECOND, track.timescale); - return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags, durationUs); + return new TrackSampleTable( + track, offsets, sizes, maximumSize, timestamps, flags, durationUs); } // Omit any sample at the end point of an edit for audio tracks. @@ -409,6 +423,11 @@ import java.util.List; System.arraycopy(sizes, startIndex, editedSizes, sampleIndex, count); System.arraycopy(flags, startIndex, editedFlags, sampleIndex, count); } + if (startIndex < endIndex && (editedFlags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) == 0) { + // Applying the edit list would require prerolling from a sync sample. + Log.w(TAG, "Ignoring edit list: edit does not start with a sync sample."); + throw new UnhandledEditListException(); + } for (int j = startIndex; j < endIndex; j++) { long ptsUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.movieTimescale); long timeInSegmentUs = @@ -424,20 +443,8 @@ import java.util.List; pts += editDuration; } long editedDurationUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.timescale); - - boolean hasSyncSample = false; - for (int i = 0; i < editedFlags.length && !hasSyncSample; i++) { - hasSyncSample |= (editedFlags[i] & C.BUFFER_FLAG_KEY_FRAME) != 0; - } - if (!hasSyncSample) { - // We don't support edit lists where the edited sample sequence doesn't contain a sync sample. - // Such edit lists are often (although not always) broken, so we ignore it and continue. - Log.w(TAG, "Ignoring edit list: Edited sample sequence does not contain a sync sample."); - Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale); - return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags, durationUs); - } - return new TrackSampleTable( + track, editedOffsets, editedSizes, editedMaximumSize, @@ -700,8 +707,18 @@ import java.util.List; throw new IllegalStateException(); } - out.format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null, - Format.NO_VALUE, 0, language, Format.NO_VALUE, null, subsampleOffsetUs, initializationData); + out.format = + Format.createTextSampleFormat( + Integer.toString(trackId), + mimeType, + /* codecs= */ null, + /* bitrate= */ Format.NO_VALUE, + /* selectionFlags= */ 0, + language, + /* accessibilityChannel= */ Format.NO_VALUE, + /* drmInitData= */ null, + subsampleOffsetUs, + initializationData); } private static void parseVideoSampleEntry(ParsableByteArray parent, int atomType, int position, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/DefaultSampleValues.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/DefaultSampleValues.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/DefaultSampleValues.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/DefaultSampleValues.java index f07a81333..1ec023735 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/DefaultSampleValues.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/DefaultSampleValues.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; /* package */ final class DefaultSampleValues { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java index 71020b3f3..536f70048 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FixedSampleSizeRechunker.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; /** * Rechunks fixed sample size media in which every sample is a key frame (e.g. uncompressed audio). @@ -108,4 +108,7 @@ import org.telegram.messenger.exoplayer2.util.Util; return new Results(offsets, sizes, maximumSize, timestamps, flags, duration); } + private FixedSampleSizeRechunker() { + // Prevent instantiation. + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 910b4db99..95e51c9cd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -13,35 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.mp4.Atom.ContainerAtom; -import org.telegram.messenger.exoplayer2.extractor.mp4.Atom.LeafAtom; -import org.telegram.messenger.exoplayer2.text.cea.CeaUtil; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom; +import com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom; +import com.google.android.exoplayer2.text.cea.CeaUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -50,7 +50,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Stack; import java.util.UUID; /** @@ -58,17 +57,9 @@ import java.util.UUID; */ public final class FragmentedMp4Extractor implements Extractor { - /** - * Factory for {@link FragmentedMp4Extractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new FragmentedMp4Extractor()}; - } - - }; + /** Factory for {@link FragmentedMp4Extractor} instances. */ + public static final ExtractorsFactory FACTORY = + () -> new Extractor[] {new FragmentedMp4Extractor()}; /** * Flags controlling the behavior of the extractor. @@ -141,7 +132,7 @@ public final class FragmentedMp4Extractor implements Extractor { // Parser state. private final ParsableByteArray atomHeader; private final byte[] extendedTypeScratch; - private final Stack containerAtoms; + private final ArrayDeque containerAtoms; private final ArrayDeque pendingMetadataSampleInfos; private final @Nullable TrackOutput additionalEmsgTrackOutput; @@ -202,8 +193,7 @@ public final class FragmentedMp4Extractor implements Extractor { @Nullable TimestampAdjuster timestampAdjuster, @Nullable Track sideloadedTrack, @Nullable DrmInitData sideloadedDrmInitData) { - this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, - Collections.emptyList()); + this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, Collections.emptyList()); } /** @@ -257,7 +247,7 @@ public final class FragmentedMp4Extractor implements Extractor { nalPrefix = new ParsableByteArray(5); nalBuffer = new ParsableByteArray(); extendedTypeScratch = new byte[16]; - containerAtoms = new Stack<>(); + containerAtoms = new ArrayDeque<>(); pendingMetadataSampleInfos = new ArrayDeque<>(); trackBundles = new SparseArray<>(); durationUs = C.TIME_UNSET; @@ -390,7 +380,7 @@ public final class FragmentedMp4Extractor implements Extractor { if (shouldParseContainerAtom(atomType)) { long endPosition = input.getPosition() + atomSize - Atom.HEADER_SIZE; - containerAtoms.add(new ContainerAtom(atomType, endPosition)); + containerAtoms.push(new ContainerAtom(atomType, endPosition)); if (atomSize == atomHeaderBytesRead) { processAtomEnded(endPosition); } else { @@ -500,7 +490,7 @@ public final class FragmentedMp4Extractor implements Extractor { for (int i = 0; i < trackCount; i++) { Track track = tracks.valueAt(i); TrackBundle trackBundle = new TrackBundle(extractorOutput.track(i, track.type)); - trackBundle.init(track, defaultSampleValuesArray.get(track.id)); + trackBundle.init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id)); trackBundles.put(track.id, trackBundle); durationUs = Math.max(durationUs, track.durationUs); } @@ -510,11 +500,23 @@ public final class FragmentedMp4Extractor implements Extractor { Assertions.checkState(trackBundles.size() == trackCount); for (int i = 0; i < trackCount; i++) { Track track = tracks.valueAt(i); - trackBundles.get(track.id).init(track, defaultSampleValuesArray.get(track.id)); + trackBundles + .get(track.id) + .init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id)); } } } + private DefaultSampleValues getDefaultSampleValues( + SparseArray defaultSampleValuesArray, int trackId) { + if (defaultSampleValuesArray.size() == 1) { + // Ignore track id if there is only one track to cope with non-matching track indices. + // See https://github.com/google/ExoPlayer/issues/4477. + return defaultSampleValuesArray.valueAt(/* index= */ 0); + } + return Assertions.checkNotNull(defaultSampleValuesArray.get(trackId)); + } + private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException { parseMoof(moof, trackBundles, flags, extendedTypeScratch); // If drm init data is sideloaded, we ignore pssh boxes. @@ -643,7 +645,7 @@ public final class FragmentedMp4Extractor implements Extractor { private static void parseTraf(ContainerAtom traf, SparseArray trackBundleArray, @Flags int flags, byte[] extendedTypeScratch) throws ParserException { LeafAtom tfhd = traf.getLeafAtomOfType(Atom.TYPE_tfhd); - TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundleArray, flags); + TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundleArray); if (trackBundle == null) { return; } @@ -794,13 +796,13 @@ public final class FragmentedMp4Extractor implements Extractor { * @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd * does not refer to any {@link TrackBundle}. */ - private static TrackBundle parseTfhd(ParsableByteArray tfhd, - SparseArray trackBundles, int flags) { + private static TrackBundle parseTfhd( + ParsableByteArray tfhd, SparseArray trackBundles) { tfhd.setPosition(Atom.HEADER_SIZE); int fullAtom = tfhd.readInt(); int atomFlags = Atom.parseFullAtomFlags(fullAtom); int trackId = tfhd.readInt(); - TrackBundle trackBundle = trackBundles.get((flags & FLAG_SIDELOADED) == 0 ? trackId : 0); + TrackBundle trackBundle = getTrackBundle(trackBundles, trackId); if (trackBundle == null) { return null; } @@ -825,6 +827,17 @@ public final class FragmentedMp4Extractor implements Extractor { return trackBundle; } + private static @Nullable TrackBundle getTrackBundle( + SparseArray trackBundles, int trackId) { + if (trackBundles.size() == 1) { + // Ignore track id if there is only one track. This is either because we have a side-loaded + // track (flag FLAG_SIDELOADED) or to cope with non-matching track indices (see + // https://github.com/google/ExoPlayer/issues/4083). + return trackBundles.valueAt(/* index= */ 0); + } + return trackBundles.get(trackId); + } + /** * Parses a tfdt atom (defined in 14496-12). * diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/MetadataUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/MetadataUtil.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/MetadataUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/MetadataUtil.java index 0be95907e..ed7c53911 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/MetadataUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/MetadataUtil.java @@ -13,16 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; +import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.ApicFrame; -import org.telegram.messenger.exoplayer2.metadata.id3.CommentFrame; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Frame; -import org.telegram.messenger.exoplayer2.metadata.id3.TextInformationFrame; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.ApicFrame; +import com.google.android.exoplayer2.metadata.id3.CommentFrame; +import com.google.android.exoplayer2.metadata.id3.Id3Frame; +import com.google.android.exoplayer2.metadata.id3.InternalFrame; +import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; /** * Parses metadata items stored in ilst atoms. @@ -68,6 +70,8 @@ import org.telegram.messenger.exoplayer2.util.Util; // Type for items that are intended for internal use by the player. private static final int TYPE_INTERNAL = Util.getIntegerCodeForString("----"); + private static final int PICTURE_TYPE_FRONT_COVER = 3; + // Standard genres. private static final String[] STANDARD_GENRES = new String[] { // These are the official ID3v1 genres. @@ -103,13 +107,13 @@ import org.telegram.messenger.exoplayer2.util.Util; /** * Parses a single ilst element from a {@link ParsableByteArray}. The element is read starting - * from the current position of the {@link ParsableByteArray}, and the position is advanced by - * the size of the element. The position is advanced even if the element's type is unrecognized. + * from the current position of the {@link ParsableByteArray}, and the position is advanced by the + * size of the element. The position is advanced even if the element's type is unrecognized. * * @param ilst Holds the data to be parsed. * @return The parsed element, or null if the element's type was not recognized. */ - public static Metadata.Entry parseIlstElement(ParsableByteArray ilst) { + public static @Nullable Metadata.Entry parseIlstElement(ParsableByteArray ilst) { int position = ilst.getPosition(); int endPosition = position + ilst.readInt(); int type = ilst.readInt(); @@ -181,20 +185,20 @@ import org.telegram.messenger.exoplayer2.util.Util; } } - private static TextInformationFrame parseTextAttribute(int type, String id, - ParsableByteArray data) { + private static @Nullable TextInformationFrame parseTextAttribute( + int type, String id, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); if (atomType == Atom.TYPE_data) { data.skipBytes(8); // version (1), flags (3), empty (4) String value = data.readNullTerminatedString(atomSize - 16); - return new TextInformationFrame(id, null, value); + return new TextInformationFrame(id, /* description= */ null, value); } Log.w(TAG, "Failed to parse text attribute: " + Atom.getAtomTypeString(type)); return null; } - private static CommentFrame parseCommentAttribute(int type, ParsableByteArray data) { + private static @Nullable CommentFrame parseCommentAttribute(int type, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); if (atomType == Atom.TYPE_data) { @@ -206,22 +210,27 @@ import org.telegram.messenger.exoplayer2.util.Util; return null; } - private static Id3Frame parseUint8Attribute(int type, String id, ParsableByteArray data, - boolean isTextInformationFrame, boolean isBoolean) { + private static @Nullable Id3Frame parseUint8Attribute( + int type, + String id, + ParsableByteArray data, + boolean isTextInformationFrame, + boolean isBoolean) { int value = parseUint8AttributeValue(data); if (isBoolean) { value = Math.min(1, value); } if (value >= 0) { - return isTextInformationFrame ? new TextInformationFrame(id, null, Integer.toString(value)) + return isTextInformationFrame + ? new TextInformationFrame(id, /* description= */ null, Integer.toString(value)) : new CommentFrame(LANGUAGE_UNDEFINED, id, Integer.toString(value)); } Log.w(TAG, "Failed to parse uint8 attribute: " + Atom.getAtomTypeString(type)); return null; } - private static TextInformationFrame parseIndexAndCountAttribute(int type, String attributeName, - ParsableByteArray data) { + private static @Nullable TextInformationFrame parseIndexAndCountAttribute( + int type, String attributeName, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); if (atomType == Atom.TYPE_data && atomSize >= 22) { @@ -233,25 +242,26 @@ import org.telegram.messenger.exoplayer2.util.Util; if (count > 0) { value += "/" + count; } - return new TextInformationFrame(attributeName, null, value); + return new TextInformationFrame(attributeName, /* description= */ null, value); } } Log.w(TAG, "Failed to parse index/count attribute: " + Atom.getAtomTypeString(type)); return null; } - private static TextInformationFrame parseStandardGenreAttribute(ParsableByteArray data) { + private static @Nullable TextInformationFrame parseStandardGenreAttribute( + ParsableByteArray data) { int genreCode = parseUint8AttributeValue(data); String genreString = (0 < genreCode && genreCode <= STANDARD_GENRES.length) ? STANDARD_GENRES[genreCode - 1] : null; if (genreString != null) { - return new TextInformationFrame("TCON", null, genreString); + return new TextInformationFrame("TCON", /* description= */ null, genreString); } Log.w(TAG, "Failed to parse standard genre code"); return null; } - private static ApicFrame parseCoverArt(ParsableByteArray data) { + private static @Nullable ApicFrame parseCoverArt(ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); if (atomType == Atom.TYPE_data) { @@ -265,13 +275,18 @@ import org.telegram.messenger.exoplayer2.util.Util; data.skipBytes(4); // empty (4) byte[] pictureData = new byte[atomSize - 16]; data.readBytes(pictureData, 0, pictureData.length); - return new ApicFrame(mimeType, null, 3 /* Cover (front) */, pictureData); + return new ApicFrame( + mimeType, + /* description= */ null, + /* pictureType= */ PICTURE_TYPE_FRONT_COVER, + pictureData); } Log.w(TAG, "Failed to parse cover art attribute"); return null; } - private static Id3Frame parseInternalAttribute(ParsableByteArray data, int endPosition) { + private static @Nullable Id3Frame parseInternalAttribute( + ParsableByteArray data, int endPosition) { String domain = null; String name = null; int dataAtomPosition = -1; @@ -293,14 +308,13 @@ import org.telegram.messenger.exoplayer2.util.Util; data.skipBytes(atomSize - 12); } } - if (!"com.apple.iTunes".equals(domain) || !"iTunSMPB".equals(name) || dataAtomPosition == -1) { - // We're only interested in iTunSMPB. + if (domain == null || name == null || dataAtomPosition == -1) { return null; } data.setPosition(dataAtomPosition); data.skipBytes(16); // size (4), type (4), version (1), flags (3), empty (4) String value = data.readNullTerminatedString(dataAtomSize - 16); - return new CommentFrame(LANGUAGE_UNDEFINED, name, value); + return new InternalFrame(domain, name, value); } private static int parseUint8AttributeValue(ParsableByteArray data) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Mp4Extractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Mp4Extractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java index bbb75a7e3..5bb5e214c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Mp4Extractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java @@ -13,50 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.GaplessInfoHolder; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.mp4.Atom.ContainerAtom; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.GaplessInfoHolder; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; -import java.util.Stack; /** * Extracts data from the MP4 container format. */ public final class Mp4Extractor implements Extractor, SeekMap { - /** - * Factory for {@link Mp4Extractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new Mp4Extractor()}; - } - - }; + /** Factory for {@link Mp4Extractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new Mp4Extractor()}; /** * Flags controlling the behavior of the extractor. @@ -101,7 +92,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { private final ParsableByteArray nalLength; private final ParsableByteArray atomHeader; - private final Stack containerAtoms; + private final ArrayDeque containerAtoms; @State private int parserState; private int atomType; @@ -137,7 +128,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { public Mp4Extractor(@Flags int flags) { this.flags = flags; atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE); - containerAtoms = new Stack<>(); + containerAtoms = new ArrayDeque<>(); nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE); nalLength = new ParsableByteArray(4); sampleTrackIndex = C.INDEX_UNSET; @@ -303,7 +294,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { if (shouldParseContainerAtom(atomType)) { long endPosition = input.getPosition() + atomSize - atomHeaderBytesRead; - containerAtoms.add(new ContainerAtom(atomType, endPosition)); + containerAtoms.push(new ContainerAtom(atomType, endPosition)); if (atomSize == atomHeaderBytesRead) { processAtomEnded(endPosition); } else { @@ -391,25 +382,21 @@ public final class Mp4Extractor implements Extractor, SeekMap { } } - for (int i = 0; i < moov.containerChildren.size(); i++) { - Atom.ContainerAtom atom = moov.containerChildren.get(i); - if (atom.type != Atom.TYPE_trak) { - continue; - } - - Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), - C.TIME_UNSET, null, (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, isQuickTime); - if (track == null) { - continue; - } - - Atom.ContainerAtom stblAtom = atom.getContainerAtomOfType(Atom.TYPE_mdia) - .getContainerAtomOfType(Atom.TYPE_minf).getContainerAtomOfType(Atom.TYPE_stbl); - TrackSampleTable trackSampleTable = AtomParsers.parseStbl(track, stblAtom, gaplessInfoHolder); - if (trackSampleTable.sampleCount == 0) { - continue; - } + boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0; + ArrayList trackSampleTables; + try { + trackSampleTables = getTrackSampleTables(moov, gaplessInfoHolder, ignoreEditLists); + } catch (AtomParsers.UnhandledEditListException e) { + // Discard gapless info as we aren't able to handle corresponding edits. + gaplessInfoHolder = new GaplessInfoHolder(); + trackSampleTables = + getTrackSampleTables(moov, gaplessInfoHolder, /* ignoreEditLists= */ true); + } + int trackCount = trackSampleTables.size(); + for (int i = 0; i < trackCount; i++) { + TrackSampleTable trackSampleTable = trackSampleTables.get(i); + Track track = trackSampleTable.track; Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type)); // Each sample has up to three bytes of overhead for the start code that replaces its length. @@ -445,6 +432,39 @@ public final class Mp4Extractor implements Extractor, SeekMap { extractorOutput.seekMap(this); } + private ArrayList getTrackSampleTables( + ContainerAtom moov, GaplessInfoHolder gaplessInfoHolder, boolean ignoreEditLists) + throws ParserException { + ArrayList trackSampleTables = new ArrayList<>(); + for (int i = 0; i < moov.containerChildren.size(); i++) { + Atom.ContainerAtom atom = moov.containerChildren.get(i); + if (atom.type != Atom.TYPE_trak) { + continue; + } + Track track = + AtomParsers.parseTrak( + atom, + moov.getLeafAtomOfType(Atom.TYPE_mvhd), + /* duration= */ C.TIME_UNSET, + /* drmInitData= */ null, + ignoreEditLists, + isQuickTime); + if (track == null) { + continue; + } + Atom.ContainerAtom stblAtom = + atom.getContainerAtomOfType(Atom.TYPE_mdia) + .getContainerAtomOfType(Atom.TYPE_minf) + .getContainerAtomOfType(Atom.TYPE_stbl); + TrackSampleTable trackSampleTable = AtomParsers.parseStbl(track, stblAtom, gaplessInfoHolder); + if (trackSampleTable.sampleCount == 0) { + continue; + } + trackSampleTables.add(trackSampleTable); + } + return trackSampleTables; + } + /** * Attempts to extract the next sample in the current mdat atom for the specified track. *

    diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/PsshAtomUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/PsshAtomUtil.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/PsshAtomUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/PsshAtomUtil.java index 546bd69ea..983c23dc3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/PsshAtomUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/PsshAtomUtil.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.nio.ByteBuffer; import java.util.UUID; @@ -49,28 +49,28 @@ public final class PsshAtomUtil { * @param data The scheme specific data. * @return The PSSH atom. */ + @SuppressWarnings("ParameterNotNullable") public static byte[] buildPsshAtom( UUID systemId, @Nullable UUID[] keyIds, @Nullable byte[] data) { - boolean buildV1Atom = keyIds != null; int dataLength = data != null ? data.length : 0; int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength; - if (buildV1Atom) { + if (keyIds != null) { psshBoxLength += 4 /* KID_count */ + (keyIds.length * 16) /* KIDs */; } ByteBuffer psshBox = ByteBuffer.allocate(psshBoxLength); psshBox.putInt(psshBoxLength); psshBox.putInt(Atom.TYPE_pssh); - psshBox.putInt(buildV1Atom ? 0x01000000 : 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */); + psshBox.putInt(keyIds != null ? 0x01000000 : 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */); psshBox.putLong(systemId.getMostSignificantBits()); psshBox.putLong(systemId.getLeastSignificantBits()); - if (buildV1Atom) { + if (keyIds != null) { psshBox.putInt(keyIds.length); for (UUID keyId : keyIds) { psshBox.putLong(keyId.getMostSignificantBits()); psshBox.putLong(keyId.getLeastSignificantBits()); } } - if (dataLength != 0) { + if (data != null && data.length != 0) { psshBox.putInt(data.length); psshBox.put(data); } // Else the last 4 bytes are a 0 DataSize. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Sniffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Sniffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java index c9f60b2b3..021c9de65 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Sniffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Track.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Track.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java index 3dd856be8..3adc5a897 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/Track.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackEncryptionBox.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackEncryptionBox.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java index 2c2fd9ec9..d39aae0c5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackEncryptionBox.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.Assertions; /** * Encapsulates information parsed from a track encryption (tenc) box or sample group description diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackFragment.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackFragment.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java index aab40d0cf..5ac673d03 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackFragment.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackSampleTable.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackSampleTable.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackSampleTable.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackSampleTable.java index 65acdb893..56851fc1e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp4/TrackSampleTable.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackSampleTable.java @@ -13,40 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.mp4; +package com.google.android.exoplayer2.extractor.mp4; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; /** * Sample table for a track in an MP4 file. */ /* package */ final class TrackSampleTable { - /** - * Number of samples. - */ + /** The track corresponding to this sample table. */ + public final Track track; + /** Number of samples. */ public final int sampleCount; - /** - * Sample offsets in bytes. - */ + /** Sample offsets in bytes. */ public final long[] offsets; - /** - * Sample sizes in bytes. - */ + /** Sample sizes in bytes. */ public final int[] sizes; - /** - * Maximum sample size in {@link #sizes}. - */ + /** Maximum sample size in {@link #sizes}. */ public final int maximumSize; - /** - * Sample timestamps in microseconds. - */ + /** Sample timestamps in microseconds. */ public final long[] timestampsUs; - /** - * Sample flags. - */ + /** Sample flags. */ public final int[] flags; /** * The duration of the track sample table in microseconds, or {@link C#TIME_UNSET} if the sample @@ -55,6 +45,7 @@ import org.telegram.messenger.exoplayer2.util.Util; public final long durationUs; public TrackSampleTable( + Track track, long[] offsets, int[] sizes, int maximumSize, @@ -65,6 +56,7 @@ import org.telegram.messenger.exoplayer2.util.Util; Assertions.checkArgument(offsets.length == timestampsUs.length); Assertions.checkArgument(flags.length == timestampsUs.length); + this.track = track; this.offsets = offsets; this.sizes = sizes; this.maximumSize = maximumSize; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/DefaultOggSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/DefaultOggSeeker.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/DefaultOggSeeker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/DefaultOggSeeker.java index 1e7f9492b..042ab681f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/DefaultOggSeeker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/DefaultOggSeeker.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.Assertions; import java.io.EOFException; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/FlacReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/FlacReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java index 25af706e0..5eb072790 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/FlacReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.FlacStreamInfo; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.FlacStreamInfo; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.Arrays; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java index 1bf7188e3..5e74eab8d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; /** @@ -31,17 +31,8 @@ import java.io.IOException; */ public class OggExtractor implements Extractor { - /** - * Factory for {@link OggExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new OggExtractor()}; - } - - }; + /** Factory for {@link OggExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new OggExtractor()}; private static final int MAX_VERIFICATION_BYTES = 8; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPacket.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPacket.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java index bcf8fa344..c7f4e9489 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPacket.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPageHeader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPageHeader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java index 476845a8d..e260a72d4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggPageHeader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggSeeker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggSeeker.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggSeeker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggSeeker.java index 454146f56..aa88e5bf8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OggSeeker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggSeeker.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.SeekMap; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OpusReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OpusReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java index 01cb4dc5a..ce3b9ea6b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/OpusReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -130,6 +130,6 @@ import java.util.List; } else { length = 10000 << length; } - return frames * length; + return (long) frames * length; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/StreamReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/StreamReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java index 2bfc38b57..d136468fa 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/StreamReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisBitArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisBitArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java index 016ade8f5..958a2ef95 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisBitArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; /** * Wraps a byte array, providing methods that allow it to be read as a vorbis bitstream. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java index 3590843de..31ac6858b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ogg.VorbisUtil.Mode; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ogg.VorbisUtil.Mode; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; import java.util.ArrayList; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisUtil.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisUtil.java index 93989e339..0235fba27 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ogg/VorbisUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisUtil.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ogg; +package com.google.android.exoplayer2.extractor.ogg; import android.util.Log; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Arrays; /** @@ -357,12 +357,12 @@ import java.util.Arrays; for (int i = 0; i < lengthMap.length; i++) { if (isSparse) { if (bitArray.readBit()) { - lengthMap[i] = bitArray.readBits(5) + 1; + lengthMap[i] = (long) (bitArray.readBits(5) + 1); } else { // entry unused lengthMap[i] = 0; } } else { // not sparse - lengthMap[i] = bitArray.readBits(5) + 1; + lengthMap[i] = (long) (bitArray.readBits(5) + 1); } } } else { @@ -392,7 +392,7 @@ import java.util.Arrays; lookupValuesCount = 0; } } else { - lookupValuesCount = entries * dimensions; + lookupValuesCount = (long) entries * dimensions; } // discard (no decoding required yet) bitArray.skipBits((int) (lookupValuesCount * valueBits)); @@ -407,6 +407,10 @@ import java.util.Arrays; return (long) Math.floor(Math.pow(entries, 1.d / dimension)); } + private VorbisUtil() { + // Prevent instantiation. + } + public static final class CodeBook { public final int dimensions; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/rawcc/RawCcExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/rawcc/RawCcExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java index 764c6634d..aa77aba30 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/rawcc/RawCcExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.rawcc; +package com.google.android.exoplayer2.extractor.rawcc; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Extractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Extractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java index 7e9d25cd4..cd806cfe0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Extractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.audio.Ac3Util; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.audio.Ac3Util; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** @@ -33,17 +33,8 @@ import java.io.IOException; */ public final class Ac3Extractor implements Extractor { - /** - * Factory for {@link Ac3Extractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new Ac3Extractor()}; - } - - }; + /** Factory for {@link Ac3Extractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new Ac3Extractor()}; /** * The maximum number of bytes to search when sniffing, excluding ID3 information, before giving diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Reader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Reader.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Reader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Reader.java index 9e2f4e979..4141f8337 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Ac3Reader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Reader.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.Ac3Util; -import org.telegram.messenger.exoplayer2.audio.Ac3Util.SyncFrameInfo; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.Ac3Util; +import com.google.android.exoplayer2.audio.Ac3Util.SyncFrameInfo; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java index 789edd256..56197730f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** @@ -33,17 +33,8 @@ import java.io.IOException; */ public final class AdtsExtractor implements Extractor { - /** - * Factory for {@link AdtsExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new AdtsExtractor()}; - } - - }; + /** Factory for {@link AdtsExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new AdtsExtractor()}; private static final int MAX_PACKET_SIZE = 200; private static final int ID3_TAG = Util.getIntegerCodeForString("ID3"); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java index 5ed50e1b3..96b964a4c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/AdtsReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.Log; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.DummyTrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.DummyTrackOutput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Arrays; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java similarity index 70% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java index dd3edb783..085e3443c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.support.annotation.IntDef; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; +import com.google.android.exoplayer2.text.cea.Cea708InitializationData; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -61,7 +62,10 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact * readers. */ public DefaultTsPayloadReaderFactory(@Flags int flags) { - this(flags, Collections.emptyList()); + this( + flags, + Collections.singletonList( + Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null))); } /** @@ -76,10 +80,6 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact */ public DefaultTsPayloadReaderFactory(@Flags int flags, List closedCaptionFormats) { this.flags = flags; - if (!isSet(FLAG_OVERRIDE_CAPTION_DESCRIPTORS) && closedCaptionFormats.isEmpty()) { - closedCaptionFormats = Collections.singletonList(Format.createTextSampleFormat(null, - MimeTypes.APPLICATION_CEA608, 0, null)); - } this.closedCaptionFormats = closedCaptionFormats; } @@ -107,7 +107,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact case TsExtractor.TS_STREAM_TYPE_HDMV_DTS: return new PesReader(new DtsReader(esInfo.language)); case TsExtractor.TS_STREAM_TYPE_H262: - return new PesReader(new H262Reader()); + return new PesReader(new H262Reader(buildUserDataReader(esInfo))); case TsExtractor.TS_STREAM_TYPE_H264: return isSet(FLAG_IGNORE_H264_STREAM) ? null : new PesReader(new H264Reader(buildSeiReader(esInfo), @@ -137,8 +137,34 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact * @return A {@link SeiReader} for closed caption tracks. */ private SeiReader buildSeiReader(EsInfo esInfo) { + return new SeiReader(getClosedCaptionFormats(esInfo)); + } + + /** + * If {@link #FLAG_OVERRIDE_CAPTION_DESCRIPTORS} is set, returns a {@link UserDataReader} for + * {@link #closedCaptionFormats}. If unset, parses the PMT descriptor information and returns a + * {@link UserDataReader} for the declared formats, or {@link #closedCaptionFormats} if the + * descriptor is not present. + * + * @param esInfo The {@link EsInfo} passed to {@link #createPayloadReader(int, EsInfo)}. + * @return A {@link UserDataReader} for closed caption tracks. + */ + private UserDataReader buildUserDataReader(EsInfo esInfo) { + return new UserDataReader(getClosedCaptionFormats(esInfo)); + } + + /** + * If {@link #FLAG_OVERRIDE_CAPTION_DESCRIPTORS} is set, returns a {@link List} of {@link + * #closedCaptionFormats}. If unset, parses the PMT descriptor information and returns a {@link + * List} for the declared formats, or {@link #closedCaptionFormats} if the descriptor is + * not present. + * + * @param esInfo The {@link EsInfo} passed to {@link #createPayloadReader(int, EsInfo)}. + * @return A {@link List} containing list of closed caption formats. + */ + private List getClosedCaptionFormats(EsInfo esInfo) { if (isSet(FLAG_OVERRIDE_CAPTION_DESCRIPTORS)) { - return new SeiReader(closedCaptionFormats); + return closedCaptionFormats; } ParsableByteArray scratchDescriptorData = new ParsableByteArray(esInfo.descriptorBytes); List closedCaptionFormats = this.closedCaptionFormats; @@ -163,21 +189,42 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact mimeType = MimeTypes.APPLICATION_CEA608; accessibilityChannel = 1; } - closedCaptionFormats.add(Format.createTextSampleFormat(null, mimeType, null, - Format.NO_VALUE, 0, language, accessibilityChannel, null)); - // Skip easy_reader(1), wide_aspect_ratio(1), reserved(14). - scratchDescriptorData.skipBytes(2); + + // easy_reader(1), wide_aspect_ratio(1), reserved(6). + byte flags = (byte) scratchDescriptorData.readUnsignedByte(); + // Skip reserved (8). + scratchDescriptorData.skipBytes(1); + + List initializationData = null; + // The wide_aspect_ratio flag only has meaning for CEA-708. + if (isDigital) { + boolean isWideAspectRatio = (flags & 0x40) != 0; + initializationData = Cea708InitializationData.buildData(isWideAspectRatio); + } + + closedCaptionFormats.add( + Format.createTextSampleFormat( + /* id= */ null, + mimeType, + /* codecs= */ null, + /* bitrate= */ Format.NO_VALUE, + /* selectionFlags= */ 0, + language, + accessibilityChannel, + /* drmInitData= */ null, + Format.OFFSET_SAMPLE_RELATIVE, + initializationData)); } } else { // Unknown descriptor. Ignore. } scratchDescriptorData.setPosition(nextDescriptorPosition); } - return new SeiReader(closedCaptionFormats); + + return closedCaptionFormats; } private boolean isSet(@Flags int flag) { return (flags & flag) != 0; } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DtsReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DtsReader.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DtsReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DtsReader.java index 95e081a03..0fc338301 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DtsReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DtsReader.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.audio.DtsUtil; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.audio.DtsUtil; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Parses a continuous DTS byte stream and extracts individual samples. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DvbSubtitleReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DvbSubtitleReader.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DvbSubtitleReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DvbSubtitleReader.java index b51bea158..0944d1810 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/DvbSubtitleReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/DvbSubtitleReader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/ElementaryStreamReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/ElementaryStreamReader.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/ElementaryStreamReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/ElementaryStreamReader.java index e4d7843cc..fa7f78c8c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/ElementaryStreamReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/ElementaryStreamReader.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Extracts individual samples from an elementary media stream, preserving original order. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H262Reader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H262Reader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index 4b8854c6b..e9827893e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H262Reader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Arrays; import java.util.Collections; @@ -36,6 +36,7 @@ public final class H262Reader implements ElementaryStreamReader { private static final int START_SEQUENCE_HEADER = 0xB3; private static final int START_EXTENSION = 0xB5; private static final int START_GROUP = 0xB8; + private static final int START_USER_DATA = 0xB2; private String formatId; private TrackOutput output; @@ -48,9 +49,13 @@ public final class H262Reader implements ElementaryStreamReader { private boolean hasOutputFormat; private long frameDurationUs; + private final UserDataReader userDataReader; + private final ParsableByteArray userDataParsable; + // State that should be reset on seek. private final boolean[] prefixFlags; private final CsdBuffer csdBuffer; + private final NalUnitTargetBuffer userData; private long totalBytesWritten; private boolean startedFirstSample; @@ -64,14 +69,29 @@ public final class H262Reader implements ElementaryStreamReader { private boolean sampleHasPicture; public H262Reader() { + this(null); + } + + public H262Reader(UserDataReader userDataReader) { + this.userDataReader = userDataReader; prefixFlags = new boolean[4]; csdBuffer = new CsdBuffer(128); + if (userDataReader != null) { + userData = new NalUnitTargetBuffer(START_USER_DATA, 128); + userDataParsable = new ParsableByteArray(); + } else { + userData = null; + userDataParsable = null; + } } @Override public void seek() { NalUnitUtil.clearPrefixFlags(prefixFlags); csdBuffer.reset(); + if (userDataReader != null) { + userData.reset(); + } totalBytesWritten = 0; startedFirstSample = false; } @@ -81,6 +101,9 @@ public final class H262Reader implements ElementaryStreamReader { idGenerator.generateNewId(); formatId = idGenerator.getFormatId(); output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_VIDEO); + if (userDataReader != null) { + userDataReader.createTracks(extractorOutput, idGenerator); + } } @Override @@ -106,16 +129,19 @@ public final class H262Reader implements ElementaryStreamReader { if (!hasOutputFormat) { csdBuffer.onData(dataArray, offset, limit); } + if (userDataReader != null) { + userData.appendToNalUnit(dataArray, offset, limit); + } return; } // We've found a start code with the following value. int startCodeValue = data.data[startCodeOffset + 3] & 0xFF; + // This is the number of bytes from the current offset to the start of the next start + // code. It may be negative if the start code started in the previously consumed data. + int lengthToStartCode = startCodeOffset - offset; if (!hasOutputFormat) { - // This is the number of bytes from the current offset to the start of the next start - // code. It may be negative if the start code started in the previously consumed data. - int lengthToStartCode = startCodeOffset - offset; if (lengthToStartCode > 0) { csdBuffer.onData(dataArray, offset, startCodeOffset); } @@ -130,7 +156,24 @@ public final class H262Reader implements ElementaryStreamReader { hasOutputFormat = true; } } + if (userDataReader != null) { + int bytesAlreadyPassed = 0; + if (lengthToStartCode > 0) { + userData.appendToNalUnit(dataArray, offset, startCodeOffset); + } else { + bytesAlreadyPassed = -lengthToStartCode; + } + if (userData.endNalUnit(bytesAlreadyPassed)) { + int unescapedLength = NalUnitUtil.unescapeStream(userData.nalData, userData.nalLength); + userDataParsable.reset(userData.nalData, unescapedLength); + userDataReader.consume(sampleTimeUs, userDataParsable); + } + + if (startCodeValue == START_USER_DATA && data.data[startCodeOffset + 2] == 0x1) { + userData.startNalUnit(startCodeValue); + } + } if (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER) { int bytesWrittenPastStartCode = limit - startCodeOffset; if (startedFirstSample && sampleHasPicture && hasOutputFormat) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H264Reader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H264Reader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java index 525b9366d..3cde946ce 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H264Reader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil.SpsData; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.ParsableNalUnitBitArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.NalUnitUtil.SpsData; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.ParsableNalUnitBitArray; import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H265Reader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H265Reader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java index d1ae0fbcb..f6ae80ba5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/H265Reader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.ParsableNalUnitBitArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.ParsableNalUnitBitArray; import java.util.Collections; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Id3Reader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Id3Reader.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Id3Reader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Id3Reader.java index 32c05ab09..98e130914 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/Id3Reader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/Id3Reader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Parses ID3 data and extracts individual text information frames. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/LatmReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/LatmReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java index 127476b9e..313e55676 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/LatmReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.support.annotation.Nullable; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Collections; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/MpegAudioReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/MpegAudioReader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/MpegAudioReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/MpegAudioReader.java index 8b1a8a884..82fb84b29 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/MpegAudioReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/MpegAudioReader.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.MpegAudioHeader; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Parses a continuous MPEG Audio byte stream and extracts individual frames. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/NalUnitTargetBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/NalUnitTargetBuffer.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/NalUnitTargetBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/NalUnitTargetBuffer.java index c1749df71..ece2fdf76 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/NalUnitTargetBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/NalUnitTargetBuffer.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.util.Arrays; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PesReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PesReader.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PesReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PesReader.java index c14dffd98..4863df42e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PesReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PesReader.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; /** * Parses PES packet data and extracts samples. diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java new file mode 100755 index 000000000..fa4be4b28 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor.ts; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import java.io.IOException; + +/** + * A reader that can extract the approximate duration from a given MPEG program stream (PS). + * + *

    This reader extracts the duration by reading system clock reference (SCR) values from the + * header of a pack at the start and at the end of the stream, calculating the difference, and + * converting that into stream duration. This reader also handles the case when a single SCR + * wraparound takes place within the stream, which can make SCR values at the beginning of the + * stream larger than SCR values at the end. This class can only be used once to read duration from + * a given stream, and the usage of the class is not thread-safe, so all calls should be made from + * the same thread. + * + *

    Note: See ISO/IEC 13818-1, Table 2-33 for details of the SCR field in pack_header. + */ +/* package */ final class PsDurationReader { + + private static final int DURATION_READ_BYTES = 20000; + + private final TimestampAdjuster scrTimestampAdjuster; + private final ParsableByteArray packetBuffer; + + private boolean isDurationRead; + private boolean isFirstScrValueRead; + private boolean isLastScrValueRead; + + private long firstScrValue; + private long lastScrValue; + private long durationUs; + + /* package */ PsDurationReader() { + scrTimestampAdjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0); + firstScrValue = C.TIME_UNSET; + lastScrValue = C.TIME_UNSET; + durationUs = C.TIME_UNSET; + packetBuffer = new ParsableByteArray(DURATION_READ_BYTES); + } + + /** Returns true if a PS duration has been read. */ + public boolean isDurationReadFinished() { + return isDurationRead; + } + + /** + * Reads a PS duration from the input. + * + *

    This reader reads the duration by reading SCR values from the header of a pack at the start + * and at the end of the stream, calculating the difference, and converting that into stream + * duration. + * + * @param input The {@link ExtractorInput} from which data should be read. + * @param seekPositionHolder If {@link Extractor#RESULT_SEEK} is returned, this holder is updated + * to hold the position of the required seek. + * @return One of the {@code RESULT_} values defined in {@link Extractor}. + * @throws IOException If an error occurred reading from the input. + * @throws InterruptedException If the thread was interrupted. + */ + public @Extractor.ReadResult int readDuration( + ExtractorInput input, PositionHolder seekPositionHolder) + throws IOException, InterruptedException { + if (!isLastScrValueRead) { + return readLastScrValue(input, seekPositionHolder); + } + if (lastScrValue == C.TIME_UNSET) { + return finishReadDuration(input); + } + if (!isFirstScrValueRead) { + return readFirstScrValue(input, seekPositionHolder); + } + if (firstScrValue == C.TIME_UNSET) { + return finishReadDuration(input); + } + + long minScrPositionUs = scrTimestampAdjuster.adjustTsTimestamp(firstScrValue); + long maxScrPositionUs = scrTimestampAdjuster.adjustTsTimestamp(lastScrValue); + durationUs = maxScrPositionUs - minScrPositionUs; + return finishReadDuration(input); + } + + /** Returns the duration last read from {@link #readDuration(ExtractorInput, PositionHolder)}. */ + public long getDurationUs() { + return durationUs; + } + + private int finishReadDuration(ExtractorInput input) { + isDurationRead = true; + input.resetPeekPosition(); + return Extractor.RESULT_CONTINUE; + } + + private int readFirstScrValue(ExtractorInput input, PositionHolder seekPositionHolder) + throws IOException, InterruptedException { + if (input.getPosition() != 0) { + seekPositionHolder.position = 0; + return Extractor.RESULT_SEEK; + } + + int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); + input.resetPeekPosition(); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + packetBuffer.setPosition(0); + packetBuffer.setLimit(bytesToRead); + + firstScrValue = readFirstScrValueFromBuffer(packetBuffer); + isFirstScrValueRead = true; + return Extractor.RESULT_CONTINUE; + } + + private long readFirstScrValueFromBuffer(ParsableByteArray packetBuffer) { + int searchStartPosition = packetBuffer.getPosition(); + int searchEndPosition = packetBuffer.limit(); + for (int searchPosition = searchStartPosition; + searchPosition < searchEndPosition - 3; + searchPosition++) { + int nextStartCode = peakIntAtPosition(packetBuffer.data, searchPosition); + if (nextStartCode == PsExtractor.PACK_START_CODE) { + long scrValue = readScrValueFromPack(packetBuffer, searchPosition + 4); + if (scrValue != C.TIME_UNSET) { + return scrValue; + } + } + } + return C.TIME_UNSET; + } + + private int readLastScrValue(ExtractorInput input, PositionHolder seekPositionHolder) + throws IOException, InterruptedException { + int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); + long bufferStartStreamPosition = input.getLength() - bytesToRead; + if (input.getPosition() != bufferStartStreamPosition) { + seekPositionHolder.position = bufferStartStreamPosition; + return Extractor.RESULT_SEEK; + } + + input.resetPeekPosition(); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + packetBuffer.setPosition(0); + packetBuffer.setLimit(bytesToRead); + + lastScrValue = readLastScrValueFromBuffer(packetBuffer); + isLastScrValueRead = true; + return Extractor.RESULT_CONTINUE; + } + + private long readLastScrValueFromBuffer(ParsableByteArray packetBuffer) { + int searchStartPosition = packetBuffer.getPosition(); + int searchEndPosition = packetBuffer.limit(); + for (int searchPosition = searchEndPosition - 4; + searchPosition >= searchStartPosition; + searchPosition--) { + int nextStartCode = peakIntAtPosition(packetBuffer.data, searchPosition); + if (nextStartCode == PsExtractor.PACK_START_CODE) { + long scrValue = readScrValueFromPack(packetBuffer, searchPosition + 4); + if (scrValue != C.TIME_UNSET) { + return scrValue; + } + } + } + return C.TIME_UNSET; + } + + private int peakIntAtPosition(byte[] data, int position) { + return (data[position] & 0xFF) << 24 + | (data[position + 1] & 0xFF) << 16 + | (data[position + 2] & 0xFF) << 8 + | (data[position + 3] & 0xFF); + } + + private long readScrValueFromPack(ParsableByteArray packetBuffer, int packHeaderStartPosition) { + packetBuffer.setPosition(packHeaderStartPosition); + if (packetBuffer.bytesLeft() < 9) { + // We require at 9 bytes for pack header to read scr value + return C.TIME_UNSET; + } + byte[] scrBytes = new byte[9]; + packetBuffer.readBytes(scrBytes, /* offset= */ 0, scrBytes.length); + if (!checkMarkerBits(scrBytes)) { + return C.TIME_UNSET; + } + return readScrValueFromPackHeader(scrBytes); + } + + private boolean checkMarkerBits(byte[] scrBytes) { + // Verify the 01xxx1xx marker on the 0th byte + if ((scrBytes[0] & 0xC4) != 0x44) { + return false; + } + // 1st byte belongs to scr field. + // Verify the xxxxx1xx marker on the 2nd byte + if ((scrBytes[2] & 0x04) != 0x04) { + return false; + } + // 3rd byte belongs to scr field. + // Verify the xxxxx1xx marker on the 4rd byte + if ((scrBytes[4] & 0x04) != 0x04) { + return false; + } + // Verify the xxxxxxx1 marker on the 5th byte + if ((scrBytes[5] & 0x01) != 0x01) { + return false; + } + // 6th and 7th bytes belongs to program_max_rate field. + // Verify the xxxxxx11 marker on the 8th byte + return (scrBytes[8] & 0x03) == 0x03; + } + + /** + * Returns the value of SCR base - 33 bits in big endian order from the PS pack header, ignoring + * the marker bits. Note: See ISO/IEC 13818-1, Table 2-33 for details of the SCR field in + * pack_header. + * + *

    We ignore SCR Ext, because it's too small to have any significance. + */ + private static long readScrValueFromPackHeader(byte[] scrBytes) { + return ((scrBytes[0] & 0b00111000L) >> 3) << 30 + | (scrBytes[0] & 0b00000011L) << 28 + | (scrBytes[1] & 0xFFL) << 20 + | ((scrBytes[2] & 0b11111000L) >> 3) << 15 + | (scrBytes[2] & 0b00000011L) << 13 + | (scrBytes[3] & 0xFFL) << 5 + | (scrBytes[4] & 0b11111000L) >> 3; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PsExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsExtractor.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PsExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsExtractor.java index e2c01e40b..49ab8de88 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/PsExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/PsExtractor.java @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.io.IOException; /** @@ -35,24 +35,20 @@ import java.io.IOException; */ public final class PsExtractor implements Extractor { - /** - * Factory for {@link PsExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { + /** Factory for {@link PsExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new PsExtractor()}; - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new PsExtractor()}; - } - - }; - - private static final int PACK_START_CODE = 0x000001BA; + /* package */ static final int PACK_START_CODE = 0x000001BA; private static final int SYSTEM_HEADER_START_CODE = 0x000001BB; private static final int PACKET_START_CODE_PREFIX = 0x000001; private static final int MPEG_PROGRAM_END_CODE = 0x000001B9; private static final int MAX_STREAM_ID_PLUS_ONE = 0x100; + + // Max search length for first audio and video track in input data. private static final long MAX_SEARCH_LENGTH = 1024 * 1024; + // Max search length for additional audio and video tracks in input data after at least one audio + // and video track has been found. + private static final long MAX_SEARCH_LENGTH_AFTER_AUDIO_AND_VIDEO_FOUND = 8 * 1024; public static final int PRIVATE_STREAM_1 = 0xBD; public static final int AUDIO_STREAM = 0xC0; @@ -63,12 +59,16 @@ public final class PsExtractor implements Extractor { private final TimestampAdjuster timestampAdjuster; private final SparseArray psPayloadReaders; // Indexed by pid private final ParsableByteArray psPacketBuffer; + private final PsDurationReader durationReader; + private boolean foundAllTracks; private boolean foundAudioTrack; private boolean foundVideoTrack; + private long lastTrackPosition; // Accessed only by the loading thread. private ExtractorOutput output; + private boolean hasOutputSeekMap; public PsExtractor() { this(new TimestampAdjuster(0)); @@ -78,6 +78,7 @@ public final class PsExtractor implements Extractor { this.timestampAdjuster = timestampAdjuster; psPacketBuffer = new ParsableByteArray(4096); psPayloadReaders = new SparseArray<>(); + durationReader = new PsDurationReader(); } // Extractor implementation. @@ -124,7 +125,6 @@ public final class PsExtractor implements Extractor { @Override public void init(ExtractorOutput output) { this.output = output; - output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); } @Override @@ -143,6 +143,13 @@ public final class PsExtractor implements Extractor { @Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { + + boolean canReadDuration = input.getLength() != C.LENGTH_UNSET; + if (canReadDuration && !durationReader.isDurationReadFinished()) { + return durationReader.readDuration(input, seekPosition); + } + maybeOutputSeekMap(); + // First peek and check what type of start code is next. if (!input.peekFully(psPacketBuffer.data, 0, 4, true)) { return RESULT_END_OF_INPUT; @@ -188,18 +195,21 @@ public final class PsExtractor implements Extractor { if (!foundAllTracks) { if (payloadReader == null) { ElementaryStreamReader elementaryStreamReader = null; - if (!foundAudioTrack && streamId == PRIVATE_STREAM_1) { + if (streamId == PRIVATE_STREAM_1) { // Private stream, used for AC3 audio. // NOTE: This may need further parsing to determine if its DTS, but that's likely only // valid for DVDs. elementaryStreamReader = new Ac3Reader(); foundAudioTrack = true; - } else if (!foundAudioTrack && (streamId & AUDIO_STREAM_MASK) == AUDIO_STREAM) { + lastTrackPosition = input.getPosition(); + } else if ((streamId & AUDIO_STREAM_MASK) == AUDIO_STREAM) { elementaryStreamReader = new MpegAudioReader(); foundAudioTrack = true; - } else if (!foundVideoTrack && (streamId & VIDEO_STREAM_MASK) == VIDEO_STREAM) { + lastTrackPosition = input.getPosition(); + } else if ((streamId & VIDEO_STREAM_MASK) == VIDEO_STREAM) { elementaryStreamReader = new H262Reader(); foundVideoTrack = true; + lastTrackPosition = input.getPosition(); } if (elementaryStreamReader != null) { TrackIdGenerator idGenerator = new TrackIdGenerator(streamId, MAX_STREAM_ID_PLUS_ONE); @@ -208,7 +218,11 @@ public final class PsExtractor implements Extractor { psPayloadReaders.put(streamId, payloadReader); } } - if ((foundAudioTrack && foundVideoTrack) || input.getPosition() > MAX_SEARCH_LENGTH) { + long maxSearchPosition = + foundAudioTrack && foundVideoTrack + ? lastTrackPosition + MAX_SEARCH_LENGTH_AFTER_AUDIO_AND_VIDEO_FOUND + : MAX_SEARCH_LENGTH; + if (input.getPosition() > maxSearchPosition) { foundAllTracks = true; output.endTracks(); } @@ -237,6 +251,13 @@ public final class PsExtractor implements Extractor { // Internals. + private void maybeOutputSeekMap() { + if (!hasOutputSeekMap) { + hasOutputSeekMap = true; + output.seekMap(new SeekMap.Unseekable(durationReader.getDurationUs())); + } + } + /** * Parses PES packet data and extracts samples. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionPayloadReader.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionPayloadReader.java index 377e0d0fa..d6e6eadf3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionPayloadReader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; /** * Reads section data. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionReader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionReader.java index 4cdfb1774..d217cfcb7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SectionReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionReader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.Util; /** * Reads section data packets and feeds the whole sections to a given {@link SectionPayloadReader}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SeiReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java similarity index 66% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SeiReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java index 9e884a14e..895c22469 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SeiReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.text.cea.CeaUtil; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.text.cea.CeaUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.List; /** @@ -52,9 +52,18 @@ import java.util.List; || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), "Invalid closed caption mime type provided: " + channelMimeType); String formatId = channelFormat.id != null ? channelFormat.id : idGenerator.getFormatId(); - output.format(Format.createTextSampleFormat(formatId, channelMimeType, null, Format.NO_VALUE, - channelFormat.selectionFlags, channelFormat.language, channelFormat.accessibilityChannel, - null)); + output.format( + Format.createTextSampleFormat( + formatId, + channelMimeType, + /* codecs= */ null, + /* bitrate= */ Format.NO_VALUE, + channelFormat.selectionFlags, + channelFormat.language, + channelFormat.accessibilityChannel, + /* drmInitData= */ null, + Format.OFFSET_SAMPLE_RELATIVE, + channelFormat.initializationData)); outputs[i] = output; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SpliceInfoSectionReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SpliceInfoSectionReader.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SpliceInfoSectionReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SpliceInfoSectionReader.java index 7148662ff..27838d4c2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/SpliceInfoSectionReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/SpliceInfoSectionReader.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; /** * Parses splice info sections as defined by SCTE35. diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java new file mode 100755 index 000000000..450b3f519 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor.ts; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import java.io.IOException; + +/** + * A reader that can extract the approximate duration from a given MPEG transport stream (TS). + * + *

    This reader extracts the duration by reading PCR values of the PCR PID packets at the start + * and at the end of the stream, calculating the difference, and converting that into stream + * duration. This reader also handles the case when a single PCR wraparound takes place within the + * stream, which can make PCR values at the beginning of the stream larger than PCR values at the + * end. This class can only be used once to read duration from a given stream, and the usage of the + * class is not thread-safe, so all calls should be made from the same thread. + */ +/* package */ final class TsDurationReader { + + private static final int DURATION_READ_PACKETS = 200; + private static final int DURATION_READ_BYTES = TsExtractor.TS_PACKET_SIZE * DURATION_READ_PACKETS; + + private final TimestampAdjuster pcrTimestampAdjuster; + private final ParsableByteArray packetBuffer; + + private boolean isDurationRead; + private boolean isFirstPcrValueRead; + private boolean isLastPcrValueRead; + + private long firstPcrValue; + private long lastPcrValue; + private long durationUs; + + /* package */ TsDurationReader() { + pcrTimestampAdjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0); + firstPcrValue = C.TIME_UNSET; + lastPcrValue = C.TIME_UNSET; + durationUs = C.TIME_UNSET; + packetBuffer = new ParsableByteArray(DURATION_READ_BYTES); + } + + /** Returns true if a TS duration has been read. */ + public boolean isDurationReadFinished() { + return isDurationRead; + } + + /** + * Reads a TS duration from the input, using the given PCR PID. + * + *

    This reader reads the duration by reading PCR values of the PCR PID packets at the start and + * at the end of the stream, calculating the difference, and converting that into stream duration. + * + * @param input The {@link ExtractorInput} from which data should be read. + * @param seekPositionHolder If {@link Extractor#RESULT_SEEK} is returned, this holder is updated + * to hold the position of the required seek. + * @param pcrPid The PID of the packet stream within this TS stream that contains PCR values. + * @return One of the {@code RESULT_} values defined in {@link Extractor}. + * @throws IOException If an error occurred reading from the input. + * @throws InterruptedException If the thread was interrupted. + */ + public @Extractor.ReadResult int readDuration( + ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid) + throws IOException, InterruptedException { + if (pcrPid <= 0) { + return finishReadDuration(input); + } + if (!isLastPcrValueRead) { + return readLastPcrValue(input, seekPositionHolder, pcrPid); + } + if (lastPcrValue == C.TIME_UNSET) { + return finishReadDuration(input); + } + if (!isFirstPcrValueRead) { + return readFirstPcrValue(input, seekPositionHolder, pcrPid); + } + if (firstPcrValue == C.TIME_UNSET) { + return finishReadDuration(input); + } + + long minPcrPositionUs = pcrTimestampAdjuster.adjustTsTimestamp(firstPcrValue); + long maxPcrPositionUs = pcrTimestampAdjuster.adjustTsTimestamp(lastPcrValue); + durationUs = maxPcrPositionUs - minPcrPositionUs; + return finishReadDuration(input); + } + + /** + * Returns the duration last read from {@link #readDuration(ExtractorInput, PositionHolder, int)}. + */ + public long getDurationUs() { + return durationUs; + } + + private int finishReadDuration(ExtractorInput input) { + isDurationRead = true; + input.resetPeekPosition(); + return Extractor.RESULT_CONTINUE; + } + + private int readFirstPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid) + throws IOException, InterruptedException { + if (input.getPosition() != 0) { + seekPositionHolder.position = 0; + return Extractor.RESULT_SEEK; + } + + int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); + input.resetPeekPosition(); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + packetBuffer.setPosition(0); + packetBuffer.setLimit(bytesToRead); + + firstPcrValue = readFirstPcrValueFromBuffer(packetBuffer, pcrPid); + isFirstPcrValueRead = true; + return Extractor.RESULT_CONTINUE; + } + + private long readFirstPcrValueFromBuffer(ParsableByteArray packetBuffer, int pcrPid) { + int searchStartPosition = packetBuffer.getPosition(); + int searchEndPosition = packetBuffer.limit(); + for (int searchPosition = searchStartPosition; + searchPosition < searchEndPosition; + searchPosition++) { + if (packetBuffer.data[searchPosition] != TsExtractor.TS_SYNC_BYTE) { + continue; + } + long pcrValue = readPcrFromPacket(packetBuffer, searchPosition, pcrPid); + if (pcrValue != C.TIME_UNSET) { + return pcrValue; + } + } + return C.TIME_UNSET; + } + + private int readLastPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid) + throws IOException, InterruptedException { + int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); + long bufferStartStreamPosition = input.getLength() - bytesToRead; + if (input.getPosition() != bufferStartStreamPosition) { + seekPositionHolder.position = bufferStartStreamPosition; + return Extractor.RESULT_SEEK; + } + + input.resetPeekPosition(); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + packetBuffer.setPosition(0); + packetBuffer.setLimit(bytesToRead); + + lastPcrValue = readLastPcrValueFromBuffer(packetBuffer, pcrPid); + isLastPcrValueRead = true; + return Extractor.RESULT_CONTINUE; + } + + private long readLastPcrValueFromBuffer(ParsableByteArray packetBuffer, int pcrPid) { + int searchStartPosition = packetBuffer.getPosition(); + int searchEndPosition = packetBuffer.limit(); + for (int searchPosition = searchEndPosition - 1; + searchPosition >= searchStartPosition; + searchPosition--) { + if (packetBuffer.data[searchPosition] != TsExtractor.TS_SYNC_BYTE) { + continue; + } + long pcrValue = readPcrFromPacket(packetBuffer, searchPosition, pcrPid); + if (pcrValue != C.TIME_UNSET) { + return pcrValue; + } + } + return C.TIME_UNSET; + } + + private static long readPcrFromPacket( + ParsableByteArray packetBuffer, int startOfPacket, int pcrPid) { + packetBuffer.setPosition(startOfPacket); + if (packetBuffer.bytesLeft() < 5) { + // Header = 4 bytes, adaptationFieldLength = 1 byte. + return C.TIME_UNSET; + } + // Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format. + int tsPacketHeader = packetBuffer.readInt(); + if ((tsPacketHeader & 0x800000) != 0) { + // transport_error_indicator != 0 means there are uncorrectable errors in this packet. + return C.TIME_UNSET; + } + int pid = (tsPacketHeader & 0x1FFF00) >> 8; + if (pid != pcrPid) { + return C.TIME_UNSET; + } + boolean adaptationFieldExists = (tsPacketHeader & 0x20) != 0; + if (!adaptationFieldExists) { + return C.TIME_UNSET; + } + + int adaptationFieldLength = packetBuffer.readUnsignedByte(); + if (adaptationFieldLength >= 7 && packetBuffer.bytesLeft() >= 7) { + int flags = packetBuffer.readUnsignedByte(); + boolean pcrFlagSet = (flags & 0x10) == 0x10; + if (pcrFlagSet) { + byte[] pcrBytes = new byte[6]; + packetBuffer.readBytes(pcrBytes, /* offset= */ 0, pcrBytes.length); + return readPcrValueFromPcrBytes(pcrBytes); + } + } + return C.TIME_UNSET; + } + + /** + * Returns the value of PCR base - first 33 bits in big endian order from the PCR bytes. + * + *

    We ignore PCR Ext, because it's too small to have any significance. + */ + private static long readPcrValueFromPcrBytes(byte[] pcrBytes) { + return (pcrBytes[0] & 0xFFL) << 25 + | (pcrBytes[1] & 0xFFL) << 17 + | (pcrBytes[2] & 0xFFL) << 9 + | (pcrBytes[3] & 0xFFL) << 1 + | (pcrBytes[4] & 0xFFL) >> 7; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 56d0815c4..47d2d7a29 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -13,30 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.support.annotation.IntDef; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory.Flags; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; -import org.telegram.messenger.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory.Flags; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -50,17 +50,8 @@ import java.util.List; */ public final class TsExtractor implements Extractor { - /** - * Factory for {@link TsExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new TsExtractor()}; - } - - }; + /** Factory for {@link TsExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new TsExtractor()}; /** * Modes for the extractor. @@ -98,8 +89,9 @@ public final class TsExtractor implements Extractor { public static final int TS_STREAM_TYPE_SPLICE_INFO = 0x86; public static final int TS_STREAM_TYPE_DVBSUBS = 0x59; - private static final int TS_PACKET_SIZE = 188; - private static final int TS_SYNC_BYTE = 0x47; // First byte of each TS packet. + public static final int TS_PACKET_SIZE = 188; + public static final int TS_SYNC_BYTE = 0x47; // First byte of each TS packet. + private static final int TS_PAT_PID = 0; private static final int MAX_PID_PLUS_ONE = 0x2000; @@ -110,20 +102,25 @@ public final class TsExtractor implements Extractor { private static final int BUFFER_SIZE = TS_PACKET_SIZE * 50; private static final int SNIFF_TS_PACKET_COUNT = 5; - @Mode private final int mode; + private final @Mode int mode; private final List timestampAdjusters; private final ParsableByteArray tsPacketBuffer; private final SparseIntArray continuityCounters; private final TsPayloadReader.Factory payloadReaderFactory; private final SparseArray tsPayloadReaders; // Indexed by pid private final SparseBooleanArray trackIds; + private final SparseBooleanArray trackPids; + private final TsDurationReader durationReader; // Accessed only by the loading thread. private ExtractorOutput output; private int remainingPmts; private boolean tracksEnded; + private boolean hasOutputSeekMap; + private boolean pendingSeekToStart; private TsPayloadReader id3Reader; private int bytesSinceLastSync; + private int pcrPid; public TsExtractor() { this(0); @@ -144,18 +141,21 @@ public final class TsExtractor implements Extractor { * {@code FLAG_*} values that control the behavior of the payload readers. */ public TsExtractor(@Mode int mode, @Flags int defaultTsPayloadReaderFlags) { - this(mode, new TimestampAdjuster(0), + this( + mode, + new TimestampAdjuster(0), new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags)); } - /** * @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT} * and {@link #MODE_HLS}. * @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps. * @param payloadReaderFactory Factory for injecting a custom set of payload readers. */ - public TsExtractor(@Mode int mode, TimestampAdjuster timestampAdjuster, + public TsExtractor( + @Mode int mode, + TimestampAdjuster timestampAdjuster, TsPayloadReader.Factory payloadReaderFactory) { this.payloadReaderFactory = Assertions.checkNotNull(payloadReaderFactory); this.mode = mode; @@ -167,8 +167,11 @@ public final class TsExtractor implements Extractor { } tsPacketBuffer = new ParsableByteArray(new byte[BUFFER_SIZE], 0); trackIds = new SparseBooleanArray(); + trackPids = new SparseBooleanArray(); tsPayloadReaders = new SparseArray<>(); continuityCounters = new SparseIntArray(); + durationReader = new TsDurationReader(); + pcrPid = -1; resetPayloadReaders(); } @@ -178,16 +181,19 @@ public final class TsExtractor implements Extractor { public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { byte[] buffer = tsPacketBuffer.data; input.peekFully(buffer, 0, TS_PACKET_SIZE * SNIFF_TS_PACKET_COUNT); - for (int j = 0; j < TS_PACKET_SIZE; j++) { - for (int i = 0; true; i++) { - if (i == SNIFF_TS_PACKET_COUNT) { - input.skipFully(j); - return true; - } - if (buffer[j + i * TS_PACKET_SIZE] != TS_SYNC_BYTE) { + for (int startPosCandidate = 0; startPosCandidate < TS_PACKET_SIZE; startPosCandidate++) { + // Try to identify at least SNIFF_TS_PACKET_COUNT packets starting with TS_SYNC_BYTE. + boolean isSyncBytePatternCorrect = true; + for (int i = 0; i < SNIFF_TS_PACKET_COUNT; i++) { + if (buffer[startPosCandidate + i * TS_PACKET_SIZE] != TS_SYNC_BYTE) { + isSyncBytePatternCorrect = false; break; } } + if (isSyncBytePatternCorrect) { + input.skipFully(startPosCandidate); + return true; + } } return false; } @@ -195,19 +201,20 @@ public final class TsExtractor implements Extractor { @Override public void init(ExtractorOutput output) { this.output = output; - output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); } @Override public void seek(long position, long timeUs) { + Assertions.checkState(mode != MODE_HLS); int timestampAdjustersCount = timestampAdjusters.size(); for (int i = 0; i < timestampAdjustersCount; i++) { timestampAdjusters.get(i).reset(); } tsPacketBuffer.reset(); continuityCounters.clear(); - // Elementary stream readers' state should be cleared to get consistent behaviours when seeking. - resetPayloadReaders(); + for (int i = 0; i < tsPayloadReaders.size(); i++) { + tsPayloadReaders.valueAt(i).seek(); + } bytesSinceLastSync = 0; } @@ -217,48 +224,36 @@ public final class TsExtractor implements Extractor { } @Override - public int read(ExtractorInput input, PositionHolder seekPosition) + public @ReadResult int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { - byte[] data = tsPacketBuffer.data; - - // Shift bytes to the start of the buffer if there isn't enough space left at the end. - if (BUFFER_SIZE - tsPacketBuffer.getPosition() < TS_PACKET_SIZE) { - int bytesLeft = tsPacketBuffer.bytesLeft(); - if (bytesLeft > 0) { - System.arraycopy(data, tsPacketBuffer.getPosition(), data, 0, bytesLeft); + if (tracksEnded) { + boolean canReadDuration = input.getLength() != C.LENGTH_UNSET && mode != MODE_HLS; + if (canReadDuration && !durationReader.isDurationReadFinished()) { + return durationReader.readDuration(input, seekPosition, pcrPid); + } + maybeOutputSeekMap(); + + if (pendingSeekToStart) { + pendingSeekToStart = false; + seek(/* position= */ 0, /* timeUs= */ 0); + if (input.getPosition() != 0) { + seekPosition.position = 0; + return RESULT_SEEK; + } } - tsPacketBuffer.reset(data, bytesLeft); } - // Read more bytes until we have at least one packet. - while (tsPacketBuffer.bytesLeft() < TS_PACKET_SIZE) { - int limit = tsPacketBuffer.limit(); - int read = input.read(data, limit, BUFFER_SIZE - limit); - if (read == C.RESULT_END_OF_INPUT) { - return RESULT_END_OF_INPUT; - } - tsPacketBuffer.setLimit(limit + read); + if (!fillBufferWithAtLeastOnePacket(input)) { + return RESULT_END_OF_INPUT; + } + + int endOfPacket = findEndOfFirstTsPacketInBuffer(); + int limit = tsPacketBuffer.limit(); + if (endOfPacket > limit) { + return RESULT_CONTINUE; } // Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format. - int limit = tsPacketBuffer.limit(); - int position = tsPacketBuffer.getPosition(); - int searchStart = position; - while (position < limit && data[position] != TS_SYNC_BYTE) { - position++; - } - tsPacketBuffer.setPosition(position); - - int endOfPacket = position + TS_PACKET_SIZE; - if (endOfPacket > limit) { - bytesSinceLastSync += position - searchStart; - if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) { - throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream."); - } - return RESULT_CONTINUE; - } - bytesSinceLastSync = 0; - int tsPacketHeader = tsPacketBuffer.readInt(); if ((tsPacketHeader & 0x800000) != 0) { // transport_error_indicator // There are uncorrectable errors in this packet. @@ -300,9 +295,18 @@ public final class TsExtractor implements Extractor { } // Read the payload. - tsPacketBuffer.setLimit(endOfPacket); - payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator); - tsPacketBuffer.setLimit(limit); + boolean wereTracksEnded = tracksEnded; + if (shouldConsumePacketPayload(pid)) { + tsPacketBuffer.setLimit(endOfPacket); + payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator); + tsPacketBuffer.setLimit(limit); + } + if (mode != MODE_HLS && !wereTracksEnded && tracksEnded) { + // We have read all tracks from all PMTs in this stream. Now seek to the beginning and read + // again to make sure we output all media, including any contained in packets prior to those + // containing the track information. + pendingSeekToStart = true; + } tsPacketBuffer.setPosition(endOfPacket); return RESULT_CONTINUE; @@ -310,6 +314,80 @@ public final class TsExtractor implements Extractor { // Internals. + private void maybeOutputSeekMap() { + if (!hasOutputSeekMap) { + hasOutputSeekMap = true; + output.seekMap(new SeekMap.Unseekable(durationReader.getDurationUs())); + } + } + + private boolean fillBufferWithAtLeastOnePacket(ExtractorInput input) + throws IOException, InterruptedException { + byte[] data = tsPacketBuffer.data; + // Shift bytes to the start of the buffer if there isn't enough space left at the end. + if (BUFFER_SIZE - tsPacketBuffer.getPosition() < TS_PACKET_SIZE) { + int bytesLeft = tsPacketBuffer.bytesLeft(); + if (bytesLeft > 0) { + System.arraycopy(data, tsPacketBuffer.getPosition(), data, 0, bytesLeft); + } + tsPacketBuffer.reset(data, bytesLeft); + } + // Read more bytes until we have at least one packet. + while (tsPacketBuffer.bytesLeft() < TS_PACKET_SIZE) { + int limit = tsPacketBuffer.limit(); + int read = input.read(data, limit, BUFFER_SIZE - limit); + if (read == C.RESULT_END_OF_INPUT) { + return false; + } + tsPacketBuffer.setLimit(limit + read); + } + return true; + } + + /** + * Returns the position of the end of the first TS packet (exclusive) in the packet buffer. + * + *

    This may be a position beyond the buffer limit if the packet has not been read fully into + * the buffer, or if no packet could be found within the buffer. + */ + private int findEndOfFirstTsPacketInBuffer() throws ParserException { + int searchStart = tsPacketBuffer.getPosition(); + int limit = tsPacketBuffer.limit(); + int syncBytePosition = findSyncBytePosition(tsPacketBuffer.data, searchStart, limit); + // Discard all bytes before the sync byte. + // If sync byte is not found, this means discard the whole buffer. + tsPacketBuffer.setPosition(syncBytePosition); + int endOfPacket = syncBytePosition + TS_PACKET_SIZE; + if (endOfPacket > limit) { + bytesSinceLastSync += syncBytePosition - searchStart; + if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) { + throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream."); + } + } else { + // We have found a packet within the buffer. + bytesSinceLastSync = 0; + } + return endOfPacket; + } + + /** + * Returns the position of the first TS_SYNC_BYTE within the range [startPosition, limitPosition) + * from the provided data array, or returns limitPosition if sync byte could not be found. + */ + private static int findSyncBytePosition(byte[] data, int startPosition, int limitPosition) { + int position = startPosition; + while (position < limitPosition && data[position] != TS_SYNC_BYTE) { + position++; + } + return position; + } + + private boolean shouldConsumePacketPayload(int packetPid) { + return mode == MODE_HLS + || tracksEnded + || !trackPids.get(packetPid, /* valueIfKeyNotFound= */ false); // It's a PSI packet + } + private void resetPayloadReaders() { trackIds.clear(); tsPayloadReaders.clear(); @@ -422,9 +500,16 @@ public final class TsExtractor implements Extractor { // section_syntax_indicator(1), '0'(1), reserved(2), section_length(12) sectionData.skipBytes(2); int programNumber = sectionData.readUnsignedShort(); + + // Skip 3 bytes (24 bits), including: // reserved (2), version_number (5), current_next_indicator (1), section_number (8), - // last_section_number (8), reserved (3), PCR_PID (13) - sectionData.skipBytes(5); + // last_section_number (8) + sectionData.skipBytes(3); + + sectionData.readBytes(pmtScratch, 2); + // reserved (3), PCR_PID (13) + pmtScratch.skipBits(3); + pcrPid = pmtScratch.readBits(13); // Read program_info_length. sectionData.readBytes(pmtScratch, 2); @@ -476,14 +561,16 @@ public final class TsExtractor implements Extractor { int trackIdCount = trackIdToPidScratch.size(); for (int i = 0; i < trackIdCount; i++) { int trackId = trackIdToPidScratch.keyAt(i); + int trackPid = trackIdToPidScratch.valueAt(i); trackIds.put(trackId, true); + trackPids.put(trackPid, true); TsPayloadReader reader = trackIdToReaderScratch.valueAt(i); if (reader != null) { if (reader != id3Reader) { reader.init(timestampAdjuster, output, new TrackIdGenerator(programNumber, trackId, MAX_PID_PLUS_ONE)); } - tsPayloadReaders.put(trackIdToPidScratch.valueAt(i), reader); + tsPayloadReaders.put(trackPid, reader); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsPayloadReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsPayloadReader.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsPayloadReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsPayloadReader.java index b610c2994..2ea25bb2e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/ts/TsPayloadReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/TsPayloadReader.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.ts; +package com.google.android.exoplayer2.extractor.ts; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.util.Collections; import java.util.List; @@ -77,8 +77,10 @@ public interface TsPayloadReader { byte[] descriptorBytes) { this.streamType = streamType; this.language = language; - this.dvbSubtitleInfos = dvbSubtitleInfos == null ? Collections.emptyList() - : Collections.unmodifiableList(dvbSubtitleInfos); + this.dvbSubtitleInfos = + dvbSubtitleInfos == null + ? Collections.emptyList() + : Collections.unmodifiableList(dvbSubtitleInfos); this.descriptorBytes = descriptorBytes; } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/UserDataReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/UserDataReader.java new file mode 100755 index 000000000..724eba1d9 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/ts/UserDataReader.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor.ts; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.text.cea.CeaUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import java.util.List; + +/** Consumes user data, outputting contained CEA-608/708 messages to a {@link TrackOutput}. */ +/* package */ final class UserDataReader { + + private static final int USER_DATA_START_CODE = 0x0001B2; + + private final List closedCaptionFormats; + private final TrackOutput[] outputs; + + public UserDataReader(List closedCaptionFormats) { + this.closedCaptionFormats = closedCaptionFormats; + outputs = new TrackOutput[closedCaptionFormats.size()]; + } + + public void createTracks( + ExtractorOutput extractorOutput, TsPayloadReader.TrackIdGenerator idGenerator) { + for (int i = 0; i < outputs.length; i++) { + idGenerator.generateNewId(); + TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT); + Format channelFormat = closedCaptionFormats.get(i); + String channelMimeType = channelFormat.sampleMimeType; + Assertions.checkArgument( + MimeTypes.APPLICATION_CEA608.equals(channelMimeType) + || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), + "Invalid closed caption mime type provided: " + channelMimeType); + output.format( + Format.createTextSampleFormat( + idGenerator.getFormatId(), + channelMimeType, + /* codecs= */ null, + /* bitrate= */ Format.NO_VALUE, + channelFormat.selectionFlags, + channelFormat.language, + channelFormat.accessibilityChannel, + /* drmInitData= */ null, + Format.OFFSET_SAMPLE_RELATIVE, + channelFormat.initializationData)); + outputs[i] = output; + } + } + + public void consume(long pesTimeUs, ParsableByteArray userDataPayload) { + if (userDataPayload.bytesLeft() < 9) { + return; + } + int userDataStartCode = userDataPayload.readInt(); + int userDataIdentifier = userDataPayload.readInt(); + int userDataTypeCode = userDataPayload.readUnsignedByte(); + if (userDataStartCode == USER_DATA_START_CODE + && userDataIdentifier == CeaUtil.USER_DATA_IDENTIFIER_GA94 + && userDataTypeCode == CeaUtil.USER_DATA_TYPE_CODE_MPEG_CC) { + CeaUtil.consumeCcData(pesTimeUs, userDataPayload, outputs); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java index 8d665f655..7d6aa7024 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.wav; +package com.google.android.exoplayer2.extractor.wav; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; /** @@ -32,17 +32,8 @@ import java.io.IOException; */ public final class WavExtractor implements Extractor { - /** - * Factory for {@link WavExtractor} instances. - */ - public static final ExtractorsFactory FACTORY = new ExtractorsFactory() { - - @Override - public Extractor[] createExtractors() { - return new Extractor[] {new WavExtractor()}; - } - - }; + /** Factory for {@link WavExtractor} instances. */ + public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new WavExtractor()}; /** Arbitrary maximum input size of 32KB, which is ~170ms of 16-bit stereo PCM audio at 48KHz. */ private static final int MAX_INPUT_SIZE = 32 * 1024; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java index edd8389c6..33db6c1e6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.wav; +package com.google.android.exoplayer2.extractor.wav; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.Util; /** Header for a WAV file. */ /* package */ final class WavHeader implements SeekMap { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeaderReader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeaderReader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index 78c87857f..176769c28 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.extractor.wav; +package com.google.android.exoplayer2.extractor.wav; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** Reads a {@code WavHeader} from an input stream; supports resuming from input failures. */ -/*package*/ final class WavHeaderReader { +/* package */ final class WavHeaderReader { private static final String TAG = "WavHeaderReader"; @@ -33,6 +33,10 @@ import java.io.IOException; private static final int TYPE_PCM = 0x0001; /** Float PCM audio data. */ private static final int TYPE_FLOAT = 0x0003; + /** 8-bit ITU-T G.711 A-law audio data. */ + private static final int TYPE_A_LAW = 0x0006; + /** 8-bit ITU-T G.711 mu-law audio data. */ + private static final int TYPE_MU_LAW = 0x0007; /** Extended WAVE format. */ private static final int TYPE_WAVE_FORMAT_EXTENSIBLE = 0xFFFE; @@ -98,6 +102,12 @@ import java.io.IOException; case TYPE_FLOAT: encoding = bitsPerSample == 32 ? C.ENCODING_PCM_FLOAT : C.ENCODING_INVALID; break; + case TYPE_A_LAW: + encoding = C.ENCODING_PCM_A_LAW; + break; + case TYPE_MU_LAW: + encoding = C.ENCODING_PCM_MU_LAW; + break; default: Log.e(TAG, "Unsupported WAV format type: " + type); return null; @@ -158,6 +168,10 @@ import java.io.IOException; wavHeader.setDataBounds(input.getPosition(), chunkHeader.size); } + private WavHeaderReader() { + // Prevent instantiation. + } + /** Container for a WAV chunk header. */ private static final class ChunkHeader { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java index a534281d3..d2c92854c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.mediacodec; +package com.google.android.exoplayer2.mediacodec; import android.annotation.TargetApi; import android.graphics.Point; @@ -25,10 +25,10 @@ import android.media.MediaCodecInfo.VideoCapabilities; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; /** * Information about a {@link MediaCodec} for a given mime type. @@ -159,6 +159,11 @@ public final class MediaCodecInfo { secure = forceSecure || (capabilities != null && isSecure(capabilities)); } + @Override + public String toString() { + return name; + } + /** * The profile levels supported by the decoder. * diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 1af26e1f7..4982f8627 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.mediacodec; +package com.google.android.exoplayer2.mediacodec; import android.annotation.TargetApi; import android.media.MediaCodec; @@ -21,31 +21,34 @@ import android.media.MediaCodec.CodecException; import android.media.MediaCodec.CryptoException; import android.media.MediaCrypto; import android.media.MediaFormat; +import android.os.Bundle; import android.os.Looper; import android.os.SystemClock; +import android.support.annotation.CheckResult; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.BaseRenderer; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.drm.DrmSession; -import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.TraceUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.BaseRenderer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.drm.DrmSession; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.TraceUtil; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; @@ -84,22 +87,64 @@ public abstract class MediaCodecRenderer extends BaseRenderer { */ public final String diagnosticInfo; + /** + * If the decoder failed to initialize and another decoder being used as a fallback also failed + * to initialize, the {@link DecoderInitializationException} for the fallback decoder. Null if + * there was no fallback decoder or no suitable decoders were found. + */ + public final @Nullable DecoderInitializationException fallbackDecoderInitializationException; + public DecoderInitializationException(Format format, Throwable cause, boolean secureDecoderRequired, int errorCode) { - super("Decoder init failed: [" + errorCode + "], " + format, cause); - this.mimeType = format.sampleMimeType; - this.secureDecoderRequired = secureDecoderRequired; - this.decoderName = null; - this.diagnosticInfo = buildCustomDiagnosticInfo(errorCode); + this( + "Decoder init failed: [" + errorCode + "], " + format, + cause, + format.sampleMimeType, + secureDecoderRequired, + /* decoderName= */ null, + buildCustomDiagnosticInfo(errorCode), + /* fallbackDecoderInitializationException= */ null); } public DecoderInitializationException(Format format, Throwable cause, boolean secureDecoderRequired, String decoderName) { - super("Decoder init failed: " + decoderName + ", " + format, cause); - this.mimeType = format.sampleMimeType; + this( + "Decoder init failed: " + decoderName + ", " + format, + cause, + format.sampleMimeType, + secureDecoderRequired, + decoderName, + Util.SDK_INT >= 21 ? getDiagnosticInfoV21(cause) : null, + /* fallbackDecoderInitializationException= */ null); + } + + private DecoderInitializationException( + String message, + Throwable cause, + String mimeType, + boolean secureDecoderRequired, + @Nullable String decoderName, + @Nullable String diagnosticInfo, + @Nullable DecoderInitializationException fallbackDecoderInitializationException) { + super(message, cause); + this.mimeType = mimeType; this.secureDecoderRequired = secureDecoderRequired; this.decoderName = decoderName; - this.diagnosticInfo = Util.SDK_INT >= 21 ? getDiagnosticInfoV21(cause) : null; + this.diagnosticInfo = diagnosticInfo; + this.fallbackDecoderInitializationException = fallbackDecoderInitializationException; + } + + @CheckResult + private DecoderInitializationException copyWithFallbackException( + DecoderInitializationException fallbackException) { + return new DecoderInitializationException( + getMessage(), + getCause(), + mimeType, + secureDecoderRequired, + decoderName, + diagnosticInfo, + fallbackException); } @TargetApi(21) @@ -117,6 +162,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } + /** Indicates no codec operating rate should be set. */ + protected static final float CODEC_OPERATING_RATE_UNSET = -1; + private static final String TAG = "MediaCodecRenderer"; /** @@ -220,6 +268,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Nullable private final DrmSessionManager drmSessionManager; private final boolean playClearSamplesWithoutKeys; + private final float assumedMinimumCodecOperatingRate; private final DecoderInputBuffer buffer; private final DecoderInputBuffer flagsOnlyBuffer; private final FormatHolder formatHolder; @@ -230,7 +279,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private DrmSession drmSession; private DrmSession pendingDrmSession; private MediaCodec codec; - private MediaCodecInfo codecInfo; + private float rendererOperatingRate; + private float codecOperatingRate; + private boolean codecConfiguredWithOperatingRate; + private @Nullable ArrayDeque availableCodecInfos; + private @Nullable DecoderInitializationException preferredDecoderInitializationException; + private @Nullable MediaCodecInfo codecInfo; private @AdaptationWorkaroundMode int codecAdaptationWorkaroundMode; private boolean codecNeedsDiscardToSpsWorkaround; private boolean codecNeedsFlushWorkaround; @@ -271,15 +325,22 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * begin in parallel with key acquisition. This parameter specifies whether the renderer is * permitted to play clear regions of encrypted media files before {@code drmSessionManager} * has obtained the keys necessary to decrypt encrypted regions of the media. + * @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by + * this renderer are assumed to meet implicitly (i.e. without the operating rate being set + * explicitly using {@link MediaFormat#KEY_OPERATING_RATE}). */ - public MediaCodecRenderer(int trackType, MediaCodecSelector mediaCodecSelector, + public MediaCodecRenderer( + int trackType, + MediaCodecSelector mediaCodecSelector, @Nullable DrmSessionManager drmSessionManager, - boolean playClearSamplesWithoutKeys) { + boolean playClearSamplesWithoutKeys, + float assumedMinimumCodecOperatingRate) { super(trackType); Assertions.checkState(Util.SDK_INT >= 16); this.mediaCodecSelector = Assertions.checkNotNull(mediaCodecSelector); this.drmSessionManager = drmSessionManager; this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; + this.assumedMinimumCodecOperatingRate = assumedMinimumCodecOperatingRate; buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance(); formatHolder = new FormatHolder(); @@ -287,6 +348,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { outputBufferInfo = new MediaCodec.BufferInfo(); codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReinitializationState = REINITIALIZATION_STATE_NONE; + codecOperatingRate = CODEC_OPERATING_RATE_UNSET; + rendererOperatingRate = 1f; } @Override @@ -318,18 +381,18 @@ public abstract class MediaCodecRenderer extends BaseRenderer { throws DecoderQueryException; /** - * Returns a {@link MediaCodecInfo} for a given format. + * Returns a list of decoders that can decode media in the specified format, in priority order. * * @param mediaCodecSelector The decoder selector. * @param format The format for which a decoder is required. * @param requiresSecureDecoder Whether a secure decoder is required. - * @return A {@link MediaCodecInfo} describing the decoder to instantiate, or null if no - * suitable decoder exists. + * @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty. * @throws DecoderQueryException Thrown if there was an error querying decoders. */ - protected MediaCodecInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, - Format format, boolean requiresSecureDecoder) throws DecoderQueryException { - return mediaCodecSelector.getDecoderInfo(format.sampleMimeType, requiresSecureDecoder); + protected List getDecoderInfos( + MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) + throws DecoderQueryException { + return mediaCodecSelector.getDecoderInfos(format, requiresSecureDecoder); } /** @@ -339,10 +402,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * @param codec The {@link MediaCodec} to configure. * @param format The format for which the codec is being configured. * @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption. + * @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if + * no codec operating rate should be set. * @throws DecoderQueryException If an error occurs querying {@code codecInfo}. */ - protected abstract void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, - MediaCrypto crypto) throws DecoderQueryException; + protected abstract void configureCodec( + MediaCodecInfo codecInfo, + MediaCodec codec, + Format format, + MediaCrypto crypto, + float codecOperatingRate) + throws DecoderQueryException; protected final void maybeInitCodec() throws ExoPlaybackException { if (codec != null || format == null) { @@ -369,78 +439,44 @@ public abstract class MediaCodecRenderer extends BaseRenderer { wrappedMediaCrypto = mediaCrypto.getWrappedMediaCrypto(); drmSessionRequiresSecureDecoder = mediaCrypto.requiresSecureDecoderComponent(mimeType); } - } - - if (codecInfo == null) { - try { - codecInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); - if (codecInfo == null && drmSessionRequiresSecureDecoder) { - // The drm session indicates that a secure decoder is required, but the device does not - // have one. Assuming that supportsFormat indicated support for the media being played, we - // know that it does not require a secure output path. Most CDM implementations allow - // playback to proceed with a non-secure decoder in this case, so we try our luck. - codecInfo = getDecoderInfo(mediaCodecSelector, format, false); - if (codecInfo != null) { - Log.w(TAG, "Drm session requires secure decoder for " + mimeType + ", but " - + "no secure decoder available. Trying to proceed with " + codecInfo.name + "."); - } + if (deviceNeedsDrmKeysToConfigureCodecWorkaround()) { + @DrmSession.State int drmSessionState = drmSession.getState(); + if (drmSessionState == DrmSession.STATE_ERROR) { + throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); + } else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) { + // Wait for keys. + return; } - } catch (DecoderQueryException e) { - throwDecoderInitError(new DecoderInitializationException(format, e, - drmSessionRequiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); - } - - if (codecInfo == null) { - throwDecoderInitError(new DecoderInitializationException(format, null, - drmSessionRequiresSecureDecoder, - DecoderInitializationException.NO_SUITABLE_DECODER_ERROR)); } } - if (!shouldInitCodec(codecInfo)) { - return; + try { + if (!initCodecWithFallback(wrappedMediaCrypto, drmSessionRequiresSecureDecoder)) { + // We can't initialize a codec yet. + return; + } + } catch (DecoderInitializationException e) { + throw ExoPlaybackException.createForRenderer(e, getIndex()); } String codecName = codecInfo.name; codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName); codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format); codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); - codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecName); + codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecInfo); codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName); codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName); codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format); - try { - long codecInitializingTimestamp = SystemClock.elapsedRealtime(); - TraceUtil.beginSection("createCodec:" + codecName); - codec = MediaCodec.createByCodecName(codecName); - TraceUtil.endSection(); - TraceUtil.beginSection("configureCodec"); - configureCodec(codecInfo, codec, format, wrappedMediaCrypto); - TraceUtil.endSection(); - TraceUtil.beginSection("startCodec"); - codec.start(); - TraceUtil.endSection(); - long codecInitializedTimestamp = SystemClock.elapsedRealtime(); - onCodecInitialized(codecName, codecInitializedTimestamp, - codecInitializedTimestamp - codecInitializingTimestamp); - getCodecBuffers(); - } catch (Exception e) { - throwDecoderInitError(new DecoderInitializationException(format, e, - drmSessionRequiresSecureDecoder, codecName)); - } - codecHotswapDeadlineMs = getState() == STATE_STARTED - ? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) : C.TIME_UNSET; + codecHotswapDeadlineMs = + getState() == STATE_STARTED + ? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) + : C.TIME_UNSET; resetInputBuffer(); resetOutputBuffer(); waitingForFirstSyncFrame = true; decoderCounters.decoderInitCount++; } - private void throwDecoderInitError(DecoderInitializationException e) - throws ExoPlaybackException { - throw ExoPlaybackException.createForRenderer(e, getIndex()); - } - protected boolean shouldInitCodec(MediaCodecInfo codecInfo) { return true; } @@ -467,9 +503,16 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } } + @Override + public final void setOperatingRate(float operatingRate) throws ExoPlaybackException { + rendererOperatingRate = operatingRate; + updateCodecOperatingRate(); + } + @Override protected void onDisabled() { format = null; + availableCodecInfos = null; try { releaseCodec(); } finally { @@ -512,6 +555,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecReceivedEos = false; codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReinitializationState = REINITIALIZATION_STATE_NONE; + codecConfiguredWithOperatingRate = false; if (codec != null) { decoderCounters.decoderReleaseCount++; try { @@ -622,6 +666,166 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } } + private boolean initCodecWithFallback(MediaCrypto crypto, boolean drmSessionRequiresSecureDecoder) + throws DecoderInitializationException { + if (availableCodecInfos == null) { + try { + availableCodecInfos = + new ArrayDeque<>(getAvailableCodecInfos(drmSessionRequiresSecureDecoder)); + preferredDecoderInitializationException = null; + } catch (DecoderQueryException e) { + throw new DecoderInitializationException( + format, + e, + drmSessionRequiresSecureDecoder, + DecoderInitializationException.DECODER_QUERY_ERROR); + } + } + + if (availableCodecInfos.isEmpty()) { + throw new DecoderInitializationException( + format, + /* cause= */ null, + drmSessionRequiresSecureDecoder, + DecoderInitializationException.NO_SUITABLE_DECODER_ERROR); + } + + while (true) { + MediaCodecInfo codecInfo = availableCodecInfos.peekFirst(); + if (!shouldInitCodec(codecInfo)) { + return false; + } + try { + initCodec(codecInfo, crypto); + return true; + } catch (Exception e) { + Log.w(TAG, "Failed to initialize decoder: " + codecInfo, e); + // This codec failed to initialize, so fall back to the next codec in the list (if any). We + // won't try to use this codec again unless there's a format change or the renderer is + // disabled and re-enabled. + availableCodecInfos.removeFirst(); + DecoderInitializationException exception = + new DecoderInitializationException( + format, e, drmSessionRequiresSecureDecoder, codecInfo.name); + if (preferredDecoderInitializationException == null) { + preferredDecoderInitializationException = exception; + } else { + preferredDecoderInitializationException = + preferredDecoderInitializationException.copyWithFallbackException(exception); + } + if (availableCodecInfos.isEmpty()) { + throw preferredDecoderInitializationException; + } + } + } + } + + private List getAvailableCodecInfos(boolean drmSessionRequiresSecureDecoder) + throws DecoderQueryException { + List codecInfos = + getDecoderInfos(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); + if (codecInfos.isEmpty() && drmSessionRequiresSecureDecoder) { + // The drm session indicates that a secure decoder is required, but the device does not + // have one. Assuming that supportsFormat indicated support for the media being played, we + // know that it does not require a secure output path. Most CDM implementations allow + // playback to proceed with a non-secure decoder in this case, so we try our luck. + codecInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */ false); + if (!codecInfos.isEmpty()) { + Log.w( + TAG, + "Drm session requires secure decoder for " + + format.sampleMimeType + + ", but no secure decoder available. Trying to proceed with " + + codecInfos + + "."); + } + } + return codecInfos; + } + + private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exception { + long codecInitializingTimestamp; + long codecInitializedTimestamp; + MediaCodec codec = null; + String name = codecInfo.name; + updateCodecOperatingRate(); + boolean configureWithOperatingRate = codecOperatingRate > assumedMinimumCodecOperatingRate; + try { + codecInitializingTimestamp = SystemClock.elapsedRealtime(); + TraceUtil.beginSection("createCodec:" + name); + codec = MediaCodec.createByCodecName(name); + TraceUtil.endSection(); + TraceUtil.beginSection("configureCodec"); + configureCodec( + codecInfo, + codec, + format, + crypto, + configureWithOperatingRate ? codecOperatingRate : CODEC_OPERATING_RATE_UNSET); + codecConfiguredWithOperatingRate = configureWithOperatingRate; + TraceUtil.endSection(); + TraceUtil.beginSection("startCodec"); + codec.start(); + TraceUtil.endSection(); + codecInitializedTimestamp = SystemClock.elapsedRealtime(); + getCodecBuffers(codec); + } catch (Exception e) { + if (codec != null) { + resetCodecBuffers(); + codec.release(); + } + throw e; + } + this.codec = codec; + this.codecInfo = codecInfo; + long elapsed = codecInitializedTimestamp - codecInitializingTimestamp; + onCodecInitialized(name, codecInitializedTimestamp, elapsed); + } + + private void getCodecBuffers(MediaCodec codec) { + if (Util.SDK_INT < 21) { + inputBuffers = codec.getInputBuffers(); + outputBuffers = codec.getOutputBuffers(); + } + } + + private void resetCodecBuffers() { + if (Util.SDK_INT < 21) { + inputBuffers = null; + outputBuffers = null; + } + } + + private ByteBuffer getInputBuffer(int inputIndex) { + if (Util.SDK_INT >= 21) { + return codec.getInputBuffer(inputIndex); + } else { + return inputBuffers[inputIndex]; + } + } + + private ByteBuffer getOutputBuffer(int outputIndex) { + if (Util.SDK_INT >= 21) { + return codec.getOutputBuffer(outputIndex); + } else { + return outputBuffers[outputIndex]; + } + } + + private boolean hasOutputBuffer() { + return outputIndex >= 0; + } + + private void resetInputBuffer() { + inputIndex = C.INDEX_UNSET; + buffer.data = null; + } + + private void resetOutputBuffer() { + outputIndex = C.INDEX_UNSET; + outputBuffer = null; + } + /** * @return Whether it may be possible to feed more input data. * @throws ExoPlaybackException If an error occurs feeding the input buffer. @@ -773,66 +977,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return true; } - private void getCodecBuffers() { - if (Util.SDK_INT < 21) { - inputBuffers = codec.getInputBuffers(); - outputBuffers = codec.getOutputBuffers(); - } - } - - private void resetCodecBuffers() { - if (Util.SDK_INT < 21) { - inputBuffers = null; - outputBuffers = null; - } - } - - private ByteBuffer getInputBuffer(int inputIndex) { - if (Util.SDK_INT >= 21) { - return codec.getInputBuffer(inputIndex); - } else { - return inputBuffers[inputIndex]; - } - } - - private ByteBuffer getOutputBuffer(int outputIndex) { - if (Util.SDK_INT >= 21) { - return codec.getOutputBuffer(outputIndex); - } else { - return outputBuffers[outputIndex]; - } - } - - private boolean hasOutputBuffer() { - return outputIndex >= 0; - } - - private void resetInputBuffer() { - inputIndex = C.INDEX_UNSET; - buffer.data = null; - } - - private void resetOutputBuffer() { - outputIndex = C.INDEX_UNSET; - outputBuffer = null; - } - - private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(DecoderInputBuffer buffer, - int adaptiveReconfigurationBytes) { - MediaCodec.CryptoInfo cryptoInfo = buffer.cryptoInfo.getFrameworkCryptoInfoV16(); - if (adaptiveReconfigurationBytes == 0) { - return cryptoInfo; - } - // There must be at least one sub-sample, although numBytesOfClearData is permitted to be - // null if it contains no clear data. Instantiate it if needed, and add the reconfiguration - // bytes to the clear byte count of the first sub-sample. - if (cryptoInfo.numBytesOfClearData == null) { - cryptoInfo.numBytesOfClearData = new int[1]; - } - cryptoInfo.numBytesOfClearData[0] += adaptiveReconfigurationBytes; - return cryptoInfo; - } - private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException { if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) { return false; @@ -911,14 +1055,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } if (!keepingCodec) { - if (codecReceivedBuffers) { - // Signal end of stream and wait for any final output buffers before re-initialization. - codecReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM; - } else { - // There aren't any final output buffers, so perform re-initialization immediately. - releaseCodec(); - maybeInitCodec(); - } + reinitializeCodec(); + } else { + updateCodecOperatingRate(); } } @@ -999,6 +1138,77 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return 0; } + /** + * Returns the {@link MediaFormat#KEY_OPERATING_RATE} value for a given renderer operating rate, + * current format and set of possible stream formats. + * + *

    The default implementation returns {@link #CODEC_OPERATING_RATE_UNSET}. + * + * @param operatingRate The renderer operating rate. + * @param format The format for which the codec is being configured. + * @param streamFormats The possible stream formats. + * @return The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if no codec operating + * rate should be set. + */ + protected float getCodecOperatingRate( + float operatingRate, Format format, Format[] streamFormats) { + return CODEC_OPERATING_RATE_UNSET; + } + + /** + * Updates the codec operating rate, and the codec itself if necessary. + * + * @throws ExoPlaybackException If an error occurs releasing or initializing a codec. + */ + private void updateCodecOperatingRate() throws ExoPlaybackException { + if (format == null || Util.SDK_INT < 23) { + return; + } + + float codecOperatingRate = + getCodecOperatingRate(rendererOperatingRate, format, getStreamFormats()); + if (this.codecOperatingRate == codecOperatingRate) { + return; + } + + this.codecOperatingRate = codecOperatingRate; + if (codec == null || codecReinitializationState != REINITIALIZATION_STATE_NONE) { + // Either no codec, or it's about to be reinitialized anyway. + } else if (codecOperatingRate == CODEC_OPERATING_RATE_UNSET + && codecConfiguredWithOperatingRate) { + // We need to clear the operating rate. The only way to do so is to instantiate a new codec + // instance. See [Internal ref: b/71987865]. + reinitializeCodec(); + } else if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET + && (codecConfiguredWithOperatingRate + || codecOperatingRate > assumedMinimumCodecOperatingRate)) { + // We need to set the operating rate, either because we've set it previously or because it's + // above the assumed minimum rate. + Bundle codecParameters = new Bundle(); + codecParameters.putFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate); + codec.setParameters(codecParameters); + codecConfiguredWithOperatingRate = true; + } + } + + /** + * Starts the process of releasing the existing codec and initializing a new one. This may occur + * immediately, or be deferred until any final output buffers have been dequeued. + * + * @throws ExoPlaybackException If an error occurs releasing or initializing a codec. + */ + private void reinitializeCodec() throws ExoPlaybackException { + availableCodecInfos = null; + if (codecReceivedBuffers) { + // Signal end of stream and wait for any final output buffers before re-initialization. + codecReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM; + } else { + // There aren't any final output buffers, so perform re-initialization immediately. + releaseCodec(); + maybeInitCodec(); + } + } + /** * @return Whether it may be possible to drain more output data. * @throws ExoPlaybackException If an error occurs draining the output buffer. @@ -1209,6 +1419,32 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return false; } + private static MediaCodec.CryptoInfo getFrameworkCryptoInfo( + DecoderInputBuffer buffer, int adaptiveReconfigurationBytes) { + MediaCodec.CryptoInfo cryptoInfo = buffer.cryptoInfo.getFrameworkCryptoInfoV16(); + if (adaptiveReconfigurationBytes == 0) { + return cryptoInfo; + } + // There must be at least one sub-sample, although numBytesOfClearData is permitted to be + // null if it contains no clear data. Instantiate it if needed, and add the reconfiguration + // bytes to the clear byte count of the first sub-sample. + if (cryptoInfo.numBytesOfClearData == null) { + cryptoInfo.numBytesOfClearData = new int[1]; + } + cryptoInfo.numBytesOfClearData[0] += adaptiveReconfigurationBytes; + return cryptoInfo; + } + + /** + * Returns whether the device needs keys to have been loaded into the {@link DrmSession} before + * codec configuration. + */ + private boolean deviceNeedsDrmKeysToConfigureCodecWorkaround() { + return "Amazon".equals(Util.MANUFACTURER) + && ("AFTM".equals(Util.MODEL) // Fire TV Stick Gen 1 + || "AFTB".equals(Util.MODEL)); // Fire TV Gen 1 + } + /** * Returns whether the decoder is known to fail when flushed. *

    @@ -1272,20 +1508,23 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } /** - * Returns whether the decoder is known to handle the propagation of the - * {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} flag incorrectly on the host device. - *

    - * If true is returned, the renderer will work around the issue by approximating end of stream + * Returns whether the decoder is known to handle the propagation of the {@link + * MediaCodec#BUFFER_FLAG_END_OF_STREAM} flag incorrectly on the host device. + * + *

    If true is returned, the renderer will work around the issue by approximating end of stream * behavior without relying on the flag being propagated through to an output buffer by the * underlying decoder. * - * @param name The name of the decoder. + * @param codecInfo Information about the {@link MediaCodec}. * @return True if the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} * propagation incorrectly on the host device. False otherwise. */ - private static boolean codecNeedsEosPropagationWorkaround(String name) { - return Util.SDK_INT <= 17 && ("OMX.rk.video_decoder.avc".equals(name) - || "OMX.allwinner.video.decoder.avc".equals(name)); + private static boolean codecNeedsEosPropagationWorkaround(MediaCodecInfo codecInfo) { + String name = codecInfo.name; + return (Util.SDK_INT <= 17 + && ("OMX.rk.video_decoder.avc".equals(name) + || "OMX.allwinner.video.decoder.avc".equals(name))) + || ("Amazon".equals(Util.MANUFACTURER) && "AFTS".equals(Util.MODEL) && codecInfo.secure); } /** diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java new file mode 100755 index 000000000..1e8783d81 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.mediacodec; + +import android.media.MediaCodec; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import java.util.Collections; +import java.util.List; + +/** + * Selector of {@link MediaCodec} instances. + */ +public interface MediaCodecSelector { + + /** + * Default implementation of {@link MediaCodecSelector}, which returns the preferred decoder for + * the given format. + */ + MediaCodecSelector DEFAULT = + new MediaCodecSelector() { + @Override + public List getDecoderInfos(Format format, boolean requiresSecureDecoder) + throws DecoderQueryException { + List decoderInfos = + MediaCodecUtil.getDecoderInfos(format.sampleMimeType, requiresSecureDecoder); + return decoderInfos.isEmpty() + ? Collections.emptyList() + : Collections.singletonList(decoderInfos.get(0)); + } + + @Override + public @Nullable MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException { + return MediaCodecUtil.getPassthroughDecoderInfo(); + } + }; + + /** + * A {@link MediaCodecSelector} that returns a list of decoders in priority order, allowing + * fallback to less preferred decoders if initialization fails. + * + *

    Note: if a hardware-accelerated video decoder fails to initialize, this selector may provide + * a software video decoder to use as a fallback. Using software decoding can be inefficient, and + * the decoder may be too slow to keep up with the playback position. + */ + MediaCodecSelector DEFAULT_WITH_FALLBACK = + new MediaCodecSelector() { + @Override + public List getDecoderInfos(Format format, boolean requiresSecureDecoder) + throws DecoderQueryException { + return MediaCodecUtil.getDecoderInfos(format.sampleMimeType, requiresSecureDecoder); + } + + @Override + public @Nullable MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException { + return MediaCodecUtil.getPassthroughDecoderInfo(); + } + }; + + /** + * Returns a list of decoders that can decode media in the specified format, in priority order. + * + * @param format The format for which a decoder is required. + * @param requiresSecureDecoder Whether a secure decoder is required. + * @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty. + * @throws DecoderQueryException Thrown if there was an error querying decoders. + */ + List getDecoderInfos(Format format, boolean requiresSecureDecoder) + throws DecoderQueryException; + + /** + * Selects a decoder to instantiate for audio passthrough. + * + * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. + * @throws DecoderQueryException Thrown if there was an error querying decoders. + */ + @Nullable + MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index fc3ee7ace..a78105c0b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.mediacodec; +package com.google.android.exoplayer2.mediacodec; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -25,10 +25,11 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.SparseIntArray; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,11 +58,9 @@ public final class MediaCodecUtil { } private static final String TAG = "MediaCodecUtil"; - private static final String GOOGLE_RAW_DECODER_NAME = "OMX.google.raw.decoder"; - private static final String MTK_RAW_DECODER_NAME = "OMX.MTK.AUDIO.DECODER.RAW"; - private static final MediaCodecInfo PASSTHROUGH_DECODER_INFO = - MediaCodecInfo.newPassthroughInstance(GOOGLE_RAW_DECODER_NAME); private static final Pattern PROFILE_PATTERN = Pattern.compile("^\\D?(\\d+)$"); + private static final RawAudioCodecComparator RAW_AUDIO_CODEC_COMPARATOR = + new RawAudioCodecComparator(); private static final HashMap> decoderInfosCache = new HashMap<>(); @@ -103,22 +102,21 @@ public final class MediaCodecUtil { /** * Returns information about a decoder suitable for audio passthrough. * - * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder - * exists. + * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. + * @throws DecoderQueryException If there was an error querying the available decoders. */ - public static MediaCodecInfo getPassthroughDecoderInfo() { - // TODO: Return null if the raw decoder doesn't exist. - return PASSTHROUGH_DECODER_INFO; + public static @Nullable MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException { + MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.AUDIO_RAW, /* secure= */ false); + return decoderInfo == null ? null : MediaCodecInfo.newPassthroughInstance(decoderInfo.name); } /** * Returns information about the preferred decoder for a given mime type. * - * @param mimeType The mime type. + * @param mimeType The MIME type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. - * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder - * exists. + * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. * @throws DecoderQueryException If there was an error querying the available decoders. */ public static @Nullable MediaCodecInfo getDecoderInfo(String mimeType, boolean secure) @@ -128,18 +126,18 @@ public final class MediaCodecUtil { } /** - * Returns all {@link MediaCodecInfo}s for the given mime type, in the order given by - * {@link MediaCodecList}. + * Returns all {@link MediaCodecInfo}s for the given mime type, in the order given by {@link + * MediaCodecList}. * - * @param mimeType The mime type. + * @param mimeType The MIME type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. - * @return A list of all @{link MediaCodecInfo}s for the given mime type, in the order - * given by {@link MediaCodecList}. + * @return A list of all {@link MediaCodecInfo}s for the given mime type, in the order given by + * {@link MediaCodecList}. * @throws DecoderQueryException If there was an error querying the available decoders. */ - public static synchronized List getDecoderInfos(String mimeType, - boolean secure) throws DecoderQueryException { + public static synchronized List getDecoderInfos(String mimeType, boolean secure) + throws DecoderQueryException { CodecKey key = new CodecKey(mimeType, secure); List cachedDecoderInfos = decoderInfosCache.get(key); if (cachedDecoderInfos != null) { @@ -165,7 +163,7 @@ public final class MediaCodecUtil { getDecoderInfosInternal(eac3Key, mediaCodecList, mimeType); decoderInfos.addAll(eac3DecoderInfos); } - applyWorkarounds(decoderInfos); + applyWorkarounds(mimeType, decoderInfos); List unmodifiableDecoderInfos = Collections.unmodifiableList(decoderInfos); decoderInfosCache.put(key, unmodifiableDecoderInfos); return unmodifiableDecoderInfos; @@ -395,20 +393,12 @@ public final class MediaCodecUtil { * Modifies a list of {@link MediaCodecInfo}s to apply workarounds where we know better than the * platform. * + * @param mimeType The MIME type of input media. * @param decoderInfos The list to modify. */ - private static void applyWorkarounds(List decoderInfos) { - if (Util.SDK_INT < 26 && decoderInfos.size() > 1 - && MTK_RAW_DECODER_NAME.equals(decoderInfos.get(0).name)) { - // Prefer the Google raw decoder over the MediaTek one [Internal: b/62337687]. - for (int i = 1; i < decoderInfos.size(); i++) { - MediaCodecInfo decoderInfo = decoderInfos.get(i); - if (GOOGLE_RAW_DECODER_NAME.equals(decoderInfo.name)) { - decoderInfos.remove(i); - decoderInfos.add(0, decoderInfo); - break; - } - } + private static void applyWorkarounds(String mimeType, List decoderInfos) { + if (MimeTypes.AUDIO_RAW.equals(mimeType)) { + Collections.sort(decoderInfos, RAW_AUDIO_CODEC_COMPARATOR); } } @@ -652,6 +642,32 @@ public final class MediaCodecUtil { } + /** + * Comparator for ordering media codecs that handle {@link MimeTypes#AUDIO_RAW} to work around + * possible inconsistent behavior across different devices. A list sorted with this comparator has + * more preferred codecs first. + */ + private static final class RawAudioCodecComparator implements Comparator { + @Override + public int compare(MediaCodecInfo a, MediaCodecInfo b) { + return scoreMediaCodecInfo(a) - scoreMediaCodecInfo(b); + } + + private static int scoreMediaCodecInfo(MediaCodecInfo mediaCodecInfo) { + String name = mediaCodecInfo.name; + if (name.startsWith("OMX.google") || name.startsWith("c2.android")) { + // Prefer generic decoders over ones provided by the device. + return -1; + } + if (Util.SDK_INT < 26 && name.equals("OMX.MTK.AUDIO.DECODER.RAW")) { + // This decoder may modify the audio, so any other compatible decoders take precedence. See + // [Internal: b/62337687]. + return 1; + } + return 0; + } + } + static { AVC_PROFILE_NUMBER_TO_CONST = new SparseIntArray(); AVC_PROFILE_NUMBER_TO_CONST.put(66, CodecProfileLevel.AVCProfileBaseline); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaFormatUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaFormatUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java index c66d66aee..3cfefc073 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaFormatUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.mediacodec; +package com.google.android.exoplayer2.mediacodec; import android.annotation.TargetApi; import android.media.MediaFormat; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.video.ColorInfo; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.video.ColorInfo; import java.nio.ByteBuffer; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/Metadata.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/Metadata.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java index efef0886b..a2ad7fe2c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/Metadata.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; import android.os.Parcel; import android.os.Parcelable; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoder.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoder.java index 78b76f0ef..7e4861a8c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoder.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; + +import android.support.annotation.Nullable; /** * Decodes metadata from binary data. @@ -24,9 +26,8 @@ public interface MetadataDecoder { * Decodes a {@link Metadata} element from the provided input buffer. * * @param inputBuffer The input buffer to decode. - * @return The decoded metadata object. - * @throws MetadataDecoderException If a problem occurred decoding the data. + * @return The decoded metadata object, or null if the metadata could not be decoded. */ - Metadata decode(MetadataInputBuffer inputBuffer) throws MetadataDecoderException; - + @Nullable + Metadata decode(MetadataInputBuffer inputBuffer); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java index 1156778ea..028a8eb89 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataDecoderFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessageDecoder; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder; -import org.telegram.messenger.exoplayer2.metadata.scte35.SpliceInfoDecoder; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder; +import com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder; +import com.google.android.exoplayer2.util.MimeTypes; /** * A factory for {@link MetadataDecoder} instances. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataInputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataInputBuffer.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataInputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataInputBuffer.java index d9a8f1b2e..a09b56565 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataInputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataInputBuffer.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; /** * A {@link DecoderInputBuffer} for a {@link MetadataDecoder}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataOutput.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataOutput.java index 957a8ebe6..b635cbc4b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataOutput.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; /** * Receives metadata output. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java index d51c790b8..152eb97e0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/MetadataRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata; +package com.google.android.exoplayer2.metadata; import android.os.Handler; import android.os.Handler.Callback; import android.os.Looper; import android.os.Message; -import org.telegram.messenger.exoplayer2.BaseRenderer; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.BaseRenderer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -46,7 +48,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { private final MetadataDecoderFactory decoderFactory; private final MetadataOutput output; - private final Handler outputHandler; + private final @Nullable Handler outputHandler; private final FormatHolder formatHolder; private final MetadataInputBuffer buffer; private final Metadata[] pendingMetadata; @@ -61,11 +63,11 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { * @param output The output. * @param outputLooper The looper associated with the thread on which the output should be called. * If the output makes use of standard Android UI components, then this should normally be the - * looper associated with the application's main thread, which can be obtained using - * {@link android.app.Activity#getMainLooper()}. Null may be passed if the output should be - * called directly on the player's internal rendering thread. + * looper associated with the application's main thread, which can be obtained using {@link + * android.app.Activity#getMainLooper()}. Null may be passed if the output should be called + * directly on the player's internal rendering thread. */ - public MetadataRenderer(MetadataOutput output, Looper outputLooper) { + public MetadataRenderer(MetadataOutput output, @Nullable Looper outputLooper) { this(output, outputLooper, MetadataDecoderFactory.DEFAULT); } @@ -73,16 +75,17 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { * @param output The output. * @param outputLooper The looper associated with the thread on which the output should be called. * If the output makes use of standard Android UI components, then this should normally be the - * looper associated with the application's main thread, which can be obtained using - * {@link android.app.Activity#getMainLooper()}. Null may be passed if the output should be - * called directly on the player's internal rendering thread. + * looper associated with the application's main thread, which can be obtained using {@link + * android.app.Activity#getMainLooper()}. Null may be passed if the output should be called + * directly on the player's internal rendering thread. * @param decoderFactory A factory from which to obtain {@link MetadataDecoder} instances. */ - public MetadataRenderer(MetadataOutput output, Looper outputLooper, - MetadataDecoderFactory decoderFactory) { + public MetadataRenderer( + MetadataOutput output, @Nullable Looper outputLooper, MetadataDecoderFactory decoderFactory) { super(C.TRACK_TYPE_METADATA); this.output = Assertions.checkNotNull(output); - this.outputHandler = outputLooper == null ? null : new Handler(outputLooper, this); + this.outputHandler = + outputLooper == null ? null : Util.createHandler(outputLooper, /* callback= */ this); this.decoderFactory = Assertions.checkNotNull(decoderFactory); formatHolder = new FormatHolder(); buffer = new MetadataInputBuffer(); @@ -125,14 +128,10 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { } else { buffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs; buffer.flip(); - try { - int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT; - pendingMetadata[index] = decoder.decode(buffer); - pendingMetadataTimestamps[index] = buffer.timeUs; - pendingMetadataCount++; - } catch (MetadataDecoderException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); - } + int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT; + pendingMetadata[index] = decoder.decode(buffer); + pendingMetadataTimestamps[index] = buffer.timeUs; + pendingMetadataCount++; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessage.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessage.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java index bec4ff1cf..7d70d9de1 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessage.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.emsg; +package com.google.android.exoplayer2.metadata.emsg; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -81,12 +83,12 @@ public final class EventMessage implements Metadata.Entry { } /* package */ EventMessage(Parcel in) { - schemeIdUri = in.readString(); - value = in.readString(); + schemeIdUri = castNonNull(in.readString()); + value = castNonNull(in.readString()); presentationTimeUs = in.readLong(); durationMs = in.readLong(); id = in.readLong(); - messageData = in.createByteArray(); + messageData = castNonNull(in.createByteArray()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java index 36259db3f..7e5125e71 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.emsg; +package com.google.android.exoplayer2.metadata.emsg; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataDecoder; -import org.telegram.messenger.exoplayer2.metadata.MetadataInputBuffer; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataDecoder; +import com.google.android.exoplayer2.metadata.MetadataInputBuffer; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageEncoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageEncoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java index 8f1ee03fb..eca498a6d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/emsg/EventMessageEncoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.emsg; +package com.google.android.exoplayer2.metadata.emsg; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ApicFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ApicFrame.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ApicFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ApicFrame.java index d18916282..53976da0d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ApicFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ApicFrame.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -29,11 +31,12 @@ public final class ApicFrame extends Id3Frame { public static final String ID = "APIC"; public final String mimeType; - public final String description; + public final @Nullable String description; public final int pictureType; public final byte[] pictureData; - public ApicFrame(String mimeType, String description, int pictureType, byte[] pictureData) { + public ApicFrame( + String mimeType, @Nullable String description, int pictureType, byte[] pictureData) { super(ID); this.mimeType = mimeType; this.description = description; @@ -43,10 +46,10 @@ public final class ApicFrame extends Id3Frame { /* package */ ApicFrame(Parcel in) { super(ID); - mimeType = in.readString(); - description = in.readString(); + mimeType = castNonNull(in.readString()); + description = castNonNull(in.readString()); pictureType = in.readInt(); - pictureData = in.createByteArray(); + pictureData = castNonNull(in.createByteArray()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/BinaryFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/BinaryFrame.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/BinaryFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/BinaryFrame.java index ebb16a105..c48829ae5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/BinaryFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/BinaryFrame.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; @@ -33,8 +35,8 @@ public final class BinaryFrame extends Id3Frame { } /* package */ BinaryFrame(Parcel in) { - super(in.readString()); - data = in.createByteArray(); + super(castNonNull(in.readString())); + data = castNonNull(in.createByteArray()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterFrame.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterFrame.java index 045d71541..7ffb6d028 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterFrame.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -54,7 +56,7 @@ public final class ChapterFrame extends Id3Frame { /* package */ ChapterFrame(Parcel in) { super(ID); - this.chapterId = in.readString(); + this.chapterId = castNonNull(in.readString()); this.startTimeMs = in.readInt(); this.endTimeMs = in.readInt(); this.startOffset = in.readLong(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterTocFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterTocFrame.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterTocFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterTocFrame.java index abed81590..c4a7c06e4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/ChapterTocFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/ChapterTocFrame.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -45,7 +47,7 @@ public final class ChapterTocFrame extends Id3Frame { /* package */ ChapterTocFrame(Parcel in) { super(ID); - this.elementId = in.readString(); + this.elementId = castNonNull(in.readString()); this.isRoot = in.readByte() != 0; this.isOrdered = in.readByte() != 0; this.children = in.createStringArray(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/CommentFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/CommentFrame.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/CommentFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/CommentFrame.java index b9c51087d..5666e4893 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/CommentFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/CommentFrame.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** * Comment ID3 frame. @@ -40,9 +42,9 @@ public final class CommentFrame extends Id3Frame { /* package */ CommentFrame(Parcel in) { super(ID); - language = in.readString(); - description = in.readString(); - text = in.readString(); + language = castNonNull(in.readString()); + description = castNonNull(in.readString()); + text = castNonNull(in.readString()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/GeobFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/GeobFrame.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/GeobFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/GeobFrame.java index bad0401ed..990d8f2e4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/GeobFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/GeobFrame.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -43,10 +45,10 @@ public final class GeobFrame extends Id3Frame { /* package */ GeobFrame(Parcel in) { super(ID); - mimeType = in.readString(); - filename = in.readString(); - description = in.readString(); - data = in.createByteArray(); + mimeType = castNonNull(in.readString()); + filename = castNonNull(in.readString()); + description = castNonNull(in.readString()); + data = castNonNull(in.createByteArray()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Decoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Decoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java index 2c7594420..914fca5ee 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Decoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; +import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataDecoder; -import org.telegram.messenger.exoplayer2.metadata.MetadataInputBuffer; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataDecoder; +import com.google.android.exoplayer2.metadata.MetadataInputBuffer; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -88,7 +89,7 @@ public final class Id3Decoder implements MetadataDecoder { private static final int ID3_TEXT_ENCODING_UTF_16BE = 2; private static final int ID3_TEXT_ENCODING_UTF_8 = 3; - private final FramePredicate framePredicate; + private final @Nullable FramePredicate framePredicate; public Id3Decoder() { this(null); @@ -97,12 +98,12 @@ public final class Id3Decoder implements MetadataDecoder { /** * @param framePredicate Determines which frames are decoded. May be null to decode all frames. */ - public Id3Decoder(FramePredicate framePredicate) { + public Id3Decoder(@Nullable FramePredicate framePredicate) { this.framePredicate = framePredicate; } @Override - public Metadata decode(MetadataInputBuffer inputBuffer) { + public @Nullable Metadata decode(MetadataInputBuffer inputBuffer) { ByteBuffer buffer = inputBuffer.data; return decode(buffer.array(), buffer.limit()); } @@ -112,9 +113,10 @@ public final class Id3Decoder implements MetadataDecoder { * * @param data The bytes to decode ID3 tags from. * @param size Amount of bytes in {@code data} to read. - * @return A {@link Metadata} object containing the decoded ID3 tags. + * @return A {@link Metadata} object containing the decoded ID3 tags, or null if the data could + * not be decoded. */ - public Metadata decode(byte[] data, int size) { + public @Nullable Metadata decode(byte[] data, int size) { List id3Frames = new ArrayList<>(); ParsableByteArray id3Data = new ParsableByteArray(data, size); @@ -156,7 +158,7 @@ public final class Id3Decoder implements MetadataDecoder { * @param data A {@link ParsableByteArray} from which the header should be read. * @return The parsed header, or null if the ID3 tag is unsupported. */ - private static Id3Header decodeHeader(ParsableByteArray data) { + private static @Nullable Id3Header decodeHeader(ParsableByteArray data) { if (data.bytesLeft() < ID3_HEADER_LENGTH) { Log.w(TAG, "Data too short to be an ID3 tag"); return null; @@ -270,8 +272,12 @@ public final class Id3Decoder implements MetadataDecoder { } } - private static Id3Frame decodeFrame(int majorVersion, ParsableByteArray id3Data, - boolean unsignedIntFrameSizeHack, int frameHeaderSize, FramePredicate framePredicate) { + private static @Nullable Id3Frame decodeFrame( + int majorVersion, + ParsableByteArray id3Data, + boolean unsignedIntFrameSizeHack, + int frameHeaderSize, + @Nullable FramePredicate framePredicate) { int frameId0 = id3Data.readUnsignedByte(); int frameId1 = id3Data.readUnsignedByte(); int frameId2 = id3Data.readUnsignedByte(); @@ -399,8 +405,8 @@ public final class Id3Decoder implements MetadataDecoder { } } - private static TextInformationFrame decodeTxxxFrame(ParsableByteArray id3Data, int frameSize) - throws UnsupportedEncodingException { + private static @Nullable TextInformationFrame decodeTxxxFrame( + ParsableByteArray id3Data, int frameSize) throws UnsupportedEncodingException { if (frameSize < 1) { // Frame is malformed. return null; @@ -422,8 +428,8 @@ public final class Id3Decoder implements MetadataDecoder { return new TextInformationFrame("TXXX", description, value); } - private static TextInformationFrame decodeTextInformationFrame(ParsableByteArray id3Data, - int frameSize, String id) throws UnsupportedEncodingException { + private static @Nullable TextInformationFrame decodeTextInformationFrame( + ParsableByteArray id3Data, int frameSize, String id) throws UnsupportedEncodingException { if (frameSize < 1) { // Frame is malformed. return null; @@ -441,7 +447,7 @@ public final class Id3Decoder implements MetadataDecoder { return new TextInformationFrame(id, null, value); } - private static UrlLinkFrame decodeWxxxFrame(ParsableByteArray id3Data, int frameSize) + private static @Nullable UrlLinkFrame decodeWxxxFrame(ParsableByteArray id3Data, int frameSize) throws UnsupportedEncodingException { if (frameSize < 1) { // Frame is malformed. @@ -552,7 +558,7 @@ public final class Id3Decoder implements MetadataDecoder { return new ApicFrame(mimeType, description, pictureType, pictureData); } - private static CommentFrame decodeCommentFrame(ParsableByteArray id3Data, int frameSize) + private static @Nullable CommentFrame decodeCommentFrame(ParsableByteArray id3Data, int frameSize) throws UnsupportedEncodingException { if (frameSize < 4) { // Frame is malformed. @@ -579,9 +585,14 @@ public final class Id3Decoder implements MetadataDecoder { return new CommentFrame(language, description, text); } - private static ChapterFrame decodeChapterFrame(ParsableByteArray id3Data, int frameSize, - int majorVersion, boolean unsignedIntFrameSizeHack, int frameHeaderSize, - FramePredicate framePredicate) throws UnsupportedEncodingException { + private static ChapterFrame decodeChapterFrame( + ParsableByteArray id3Data, + int frameSize, + int majorVersion, + boolean unsignedIntFrameSizeHack, + int frameHeaderSize, + @Nullable FramePredicate framePredicate) + throws UnsupportedEncodingException { int framePosition = id3Data.getPosition(); int chapterIdEndIndex = indexOfZeroByte(id3Data.data, framePosition); String chapterId = new String(id3Data.data, framePosition, chapterIdEndIndex - framePosition, @@ -614,9 +625,14 @@ public final class Id3Decoder implements MetadataDecoder { return new ChapterFrame(chapterId, startTime, endTime, startOffset, endOffset, subFrameArray); } - private static ChapterTocFrame decodeChapterTOCFrame(ParsableByteArray id3Data, int frameSize, - int majorVersion, boolean unsignedIntFrameSizeHack, int frameHeaderSize, - FramePredicate framePredicate) throws UnsupportedEncodingException { + private static ChapterTocFrame decodeChapterTOCFrame( + ParsableByteArray id3Data, + int frameSize, + int majorVersion, + boolean unsignedIntFrameSizeHack, + int frameHeaderSize, + @Nullable FramePredicate framePredicate) + throws UnsupportedEncodingException { int framePosition = id3Data.getPosition(); int elementIdEndIndex = indexOfZeroByte(id3Data.data, framePosition); String elementId = new String(id3Data.data, framePosition, elementIdEndIndex - framePosition, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Frame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Frame.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Frame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Frame.java index d4eb0dc43..27ea833de 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/Id3Frame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Frame.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.metadata.Metadata; /** * Base class for ID3 frames. @@ -29,7 +28,7 @@ public abstract class Id3Frame implements Metadata.Entry { public final String id; public Id3Frame(String id) { - this.id = Assertions.checkNotNull(id); + this.id = id; } @Override diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/InternalFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/InternalFrame.java new file mode 100755 index 000000000..c191676ce --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/InternalFrame.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; + +import android.os.Parcel; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.Util; + +/** Internal ID3 frame that is intended for use by the player. */ +public final class InternalFrame extends Id3Frame { + + public static final String ID = "----"; + + public final String domain; + public final String description; + public final String text; + + public InternalFrame(String domain, String description, String text) { + super(ID); + this.domain = domain; + this.description = description; + this.text = text; + } + + /* package */ InternalFrame(Parcel in) { + super(ID); + domain = castNonNull(in.readString()); + description = castNonNull(in.readString()); + text = castNonNull(in.readString()); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + InternalFrame other = (InternalFrame) obj; + return Util.areEqual(description, other.description) + && Util.areEqual(domain, other.domain) + && Util.areEqual(text, other.text); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + (domain != null ? domain.hashCode() : 0); + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + (text != null ? text.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return id + ": domain=" + domain + ", description=" + description; + } + + // Parcelable implementation. + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(id); + dest.writeString(domain); + dest.writeString(text); + } + + public static final Creator CREATOR = + new Creator() { + + @Override + public InternalFrame createFromParcel(Parcel in) { + return new InternalFrame(in); + } + + @Override + public InternalFrame[] newArray(int size) { + return new InternalFrame[size]; + } + }; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/PrivFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/PrivFrame.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/PrivFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/PrivFrame.java index f7c4c872d..a10ce229d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/PrivFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/PrivFrame.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -39,8 +41,8 @@ public final class PrivFrame extends Id3Frame { /* package */ PrivFrame(Parcel in) { super(ID); - owner = in.readString(); - privateData = in.createByteArray(); + owner = castNonNull(in.readString()); + privateData = castNonNull(in.createByteArray()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/TextInformationFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/TextInformationFrame.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/TextInformationFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/TextInformationFrame.java index 89908fd9d..62175ee90 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/TextInformationFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/TextInformationFrame.java @@ -13,31 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** * Text information ID3 frame. */ public final class TextInformationFrame extends Id3Frame { - public final String description; + public final @Nullable String description; public final String value; - public TextInformationFrame(String id, String description, String value) { + public TextInformationFrame(String id, @Nullable String description, String value) { super(id); this.description = description; this.value = value; } /* package */ TextInformationFrame(Parcel in) { - super(in.readString()); + super(castNonNull(in.readString())); description = in.readString(); - value = in.readString(); + value = castNonNull(in.readString()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/UrlLinkFrame.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/UrlLinkFrame.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/UrlLinkFrame.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/UrlLinkFrame.java index 6d505612f..4b35131be 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/id3/UrlLinkFrame.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/id3/UrlLinkFrame.java @@ -13,31 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.id3; +package com.google.android.exoplayer2.metadata.id3; + +import static com.google.android.exoplayer2.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** * Url link ID3 frame. */ public final class UrlLinkFrame extends Id3Frame { - public final String description; + public final @Nullable String description; public final String url; - public UrlLinkFrame(String id, String description, String url) { + public UrlLinkFrame(String id, @Nullable String description, String url) { super(id); this.description = description; this.url = url; } /* package */ UrlLinkFrame(Parcel in) { - super(in.readString()); + super(castNonNull(in.readString())); description = in.readString(); - url = in.readString(); + url = castNonNull(in.readString()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/PrivateCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/PrivateCommand.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/PrivateCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/PrivateCommand.java index 8da3b3feb..4334fa99c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/PrivateCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/PrivateCommand.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; import android.os.Parcel; import android.os.Parcelable; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.ParsableByteArray; /** * Represents a private command as defined in SCTE35, Section 9.3.6. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceCommand.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceCommand.java index e7da29b0b..b0c3e34cd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceCommand.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; -import org.telegram.messenger.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.Metadata; /** * Superclass for SCTE35 splice commands. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInfoDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInfoDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java index ca4d34d3d..d6fc4f6c1 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInfoDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataDecoder; -import org.telegram.messenger.exoplayer2.metadata.MetadataDecoderException; -import org.telegram.messenger.exoplayer2.metadata.MetadataInputBuffer; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataDecoder; +import com.google.android.exoplayer2.metadata.MetadataInputBuffer; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.nio.ByteBuffer; /** @@ -46,7 +45,7 @@ public final class SpliceInfoDecoder implements MetadataDecoder { } @Override - public Metadata decode(MetadataInputBuffer inputBuffer) throws MetadataDecoderException { + public Metadata decode(MetadataInputBuffer inputBuffer) { // Internal timestamps adjustment. if (timestampAdjuster == null || inputBuffer.subsampleOffsetUs != timestampAdjuster.getTimestampOffsetUs()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInsertCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInsertCommand.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInsertCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInsertCommand.java index 7d3a2f6a0..6f56d3b68 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceInsertCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInsertCommand.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; import android.os.Parcel; import android.os.Parcelable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceNullCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceNullCommand.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceNullCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceNullCommand.java index 7fedf85c8..461d49ebb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceNullCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceNullCommand.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; import android.os.Parcel; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceScheduleCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceScheduleCommand.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceScheduleCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceScheduleCommand.java index 29c5b7469..8696909c9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/SpliceScheduleCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceScheduleCommand.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; import android.os.Parcel; import android.os.Parcelable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/TimeSignalCommand.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/TimeSignalCommand.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/TimeSignalCommand.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/TimeSignalCommand.java index 300bcbc34..e233a276e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/metadata/scte35/TimeSignalCommand.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/metadata/scte35/TimeSignalCommand.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.metadata.scte35; +package com.google.android.exoplayer2.metadata.scte35; import android.os.Parcel; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; /** * Represents a time signal command as defined in SCTE35, Section 9.3.4. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ActionFile.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ActionFile.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java index 2306f6d0d..e37e09a09 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ActionFile.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; -import org.telegram.messenger.exoplayer2.offline.DownloadAction.Deserializer; -import org.telegram.messenger.exoplayer2.util.AtomicFile; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.offline.DownloadAction.Deserializer; +import com.google.android.exoplayer2.util.AtomicFile; +import com.google.android.exoplayer2.util.Util; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java similarity index 72% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadAction.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java index 8c4c43464..20b786078 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadAction.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.Assertions; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -24,6 +25,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** Contains the necessary parameters for a download or remove action. */ public abstract class DownloadAction { @@ -50,6 +53,48 @@ public abstract class DownloadAction { throws IOException; } + private static @Nullable Deserializer[] defaultDeserializers; + + /** Returns available default {@link Deserializer}s. */ + public static synchronized Deserializer[] getDefaultDeserializers() { + if (defaultDeserializers != null) { + return defaultDeserializers; + } + Deserializer[] deserializers = new Deserializer[4]; + int count = 0; + deserializers[count++] = ProgressiveDownloadAction.DESERIALIZER; + Class clazz; + // Full class names used for constructor args so the LINT rule triggers if any of them move. + try { + // LINT.IfChange + clazz = Class.forName("com.google.android.exoplayer2.source.dash.offline.DashDownloadAction"); + // LINT.ThenChange(../../../../../../../../../dash/proguard-rules.txt) + deserializers[count++] = getDeserializer(clazz); + } catch (Exception e) { + // Do nothing. + } + try { + // LINT.IfChange + clazz = Class.forName("com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction"); + // LINT.ThenChange(../../../../../../../../../hls/proguard-rules.txt) + deserializers[count++] = getDeserializer(clazz); + } catch (Exception e) { + // Do nothing. + } + try { + // LINT.IfChange + clazz = + Class.forName( + "com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction"); + // LINT.ThenChange(../../../../../../../../../smoothstreaming/proguard-rules.txt) + deserializers[count++] = getDeserializer(clazz); + } catch (Exception e) { + // Do nothing. + } + defaultDeserializers = Arrays.copyOf(Assertions.checkNotNull(deserializers), count); + return defaultDeserializers; + } + /** * Deserializes one action that was serialized with {@link #serializeToStream(DownloadAction, * OutputStream)} from the {@code input}, using the {@link Deserializer}s that supports the @@ -132,11 +177,16 @@ public abstract class DownloadAction { return uri.equals(other.uri); } + /** Returns keys of tracks to be downloaded. */ + public List getKeys() { + return Collections.emptyList(); + } + /** Serializes itself into the {@code output}. */ protected abstract void writeToStream(DataOutputStream output) throws IOException; /** Creates a {@link Downloader} with the given parameters. */ - protected abstract Downloader createDownloader( + public abstract Downloader createDownloader( DownloaderConstructorHelper downloaderConstructorHelper); @Override @@ -160,4 +210,9 @@ public abstract class DownloadAction { return result; } + private static Deserializer getDeserializer(Class clazz) + throws NoSuchFieldException, IllegalAccessException { + Object value = clazz.getDeclaredField("DESERIALIZER").get(null); + return (Deserializer) Assertions.checkNotNull(value); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadException.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadException.java index 08d20e063..983727c14 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java index cd874bcec..f6157c1dc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.os.Handler; import android.os.Looper; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.TrackGroupArray; import java.io.IOException; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadManager.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadManager.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java index 11de6908b..dcfb8a8cb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadManager.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; -import static org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState.STATE_CANCELED; -import static org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState.STATE_COMPLETED; -import static org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState.STATE_FAILED; -import static org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState.STATE_QUEUED; -import static org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState.STATE_STARTED; +import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_CANCELED; +import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_COMPLETED; +import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_FAILED; +import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_QUEUED; +import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_STARTED; import android.os.ConditionVariable; import android.os.Handler; @@ -28,12 +28,12 @@ import android.os.Looper; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.offline.DownloadAction.Deserializer; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.offline.DownloadAction.Deserializer; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -108,7 +108,8 @@ public final class DownloadManager { * @param upstreamDataSourceFactory A {@link DataSource.Factory} for creating data sources for * downloading upstream data. * @param actionSaveFile File to save active actions. - * @param deserializers Used to deserialize {@link DownloadAction}s. + * @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link + * DownloadAction#getDefaultDeserializers()} is used instead. */ public DownloadManager( Cache cache, @@ -127,7 +128,8 @@ public final class DownloadManager { * @param constructorHelper A {@link DownloaderConstructorHelper} to create {@link Downloader}s * for downloading data. * @param actionFile The file in which active actions are saved. - * @param deserializers Used to deserialize {@link DownloadAction}s. + * @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link + * DownloadAction#getDefaultDeserializers()} is used instead. */ public DownloadManager( DownloaderConstructorHelper constructorHelper, @@ -149,7 +151,8 @@ public final class DownloadManager { * @param maxSimultaneousDownloads The maximum number of simultaneous download tasks. * @param minRetryCount The minimum number of times a task must be retried before failing. * @param actionFile The file in which active actions are saved. - * @param deserializers Used to deserialize {@link DownloadAction}s. + * @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link + * DownloadAction#getDefaultDeserializers()} is used instead. */ public DownloadManager( DownloaderConstructorHelper constructorHelper, @@ -157,13 +160,12 @@ public final class DownloadManager { int minRetryCount, File actionFile, Deserializer... deserializers) { - Assertions.checkArgument(deserializers.length > 0, "At least one Deserializer is required."); - this.downloaderConstructorHelper = constructorHelper; this.maxActiveDownloadTasks = maxSimultaneousDownloads; this.minRetryCount = minRetryCount; this.actionFile = new ActionFile(actionFile); - this.deserializers = deserializers; + this.deserializers = + deserializers.length > 0 ? deserializers : DownloadAction.getDefaultDeserializers(); this.downloadsStopped = true; tasks = new ArrayList<>(); @@ -262,12 +264,23 @@ public final class DownloadManager { return task.id; } - /** Returns the current number of tasks. */ + /** Returns the number of tasks. */ public int getTaskCount() { Assertions.checkState(!released); return tasks.size(); } + /** Returns the number of download tasks. */ + public int getDownloadCount() { + int count = 0; + for (int i = 0; i < tasks.size(); i++) { + if (!tasks.get(i).action.isRemoveAction) { + count++; + } + } + return count; + } + /** Returns the state of a task, or null if no such task exists */ public @Nullable TaskState getTaskState(int taskId) { Assertions.checkState(!released); @@ -762,7 +775,7 @@ public final class DownloadManager { private void stop() { if (changeStateAndNotify(STATE_STARTED, STATE_STARTED_STOPPING)) { logd("Stopping", this); - thread.interrupt(); + cancelDownload(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadService.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadService.java similarity index 63% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadService.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadService.java index 8eb2fab6d..f7ca793b2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloadService.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloadService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.app.Notification; import android.app.Service; @@ -25,12 +25,12 @@ import android.os.Looper; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.util.Log; -import org.telegram.messenger.exoplayer2.offline.DownloadManager.TaskState; -import org.telegram.messenger.exoplayer2.scheduler.Requirements; -import org.telegram.messenger.exoplayer2.scheduler.RequirementsWatcher; -import org.telegram.messenger.exoplayer2.scheduler.Scheduler; -import org.telegram.messenger.exoplayer2.util.NotificationUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.offline.DownloadManager.TaskState; +import com.google.android.exoplayer2.scheduler.Requirements; +import com.google.android.exoplayer2.scheduler.RequirementsWatcher; +import com.google.android.exoplayer2.scheduler.Scheduler; +import com.google.android.exoplayer2.util.NotificationUtil; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.HashMap; @@ -44,21 +44,20 @@ public abstract class DownloadService extends Service { /** Starts a download service, adding a new {@link DownloadAction} to be executed. */ public static final String ACTION_ADD = "com.google.android.exoplayer.downloadService.action.ADD"; + /** Reloads the download requirements. */ + public static final String ACTION_RELOAD_REQUIREMENTS = + "com.google.android.exoplayer.downloadService.action.RELOAD_REQUIREMENTS"; + /** Like {@link #ACTION_INIT}, but with {@link #KEY_FOREGROUND} implicitly set to true. */ private static final String ACTION_RESTART = "com.google.android.exoplayer.downloadService.action.RESTART"; - /** Starts download tasks. */ - private static final String ACTION_START_DOWNLOADS = - "com.google.android.exoplayer.downloadService.action.START_DOWNLOADS"; - - /** Stops download tasks. */ - private static final String ACTION_STOP_DOWNLOADS = - "com.google.android.exoplayer.downloadService.action.STOP_DOWNLOADS"; - /** Key for the {@link DownloadAction} in an {@link #ACTION_ADD} intent. */ public static final String KEY_DOWNLOAD_ACTION = "download_action"; + /** Invalid foreground notification id which can be used to run the service in the background. */ + public static final int FOREGROUND_NOTIFICATION_ID_NONE = 0; + /** * Key for a boolean flag in any intent to indicate whether the service was started in the * foreground. If set, the service is guaranteed to call {@link #startForeground(int, @@ -77,8 +76,10 @@ public abstract class DownloadService extends Service { // tasks the resume more quickly than when relying on the scheduler alone. private static final HashMap, RequirementsHelper> requirementsHelpers = new HashMap<>(); + private static final Requirements DEFAULT_REQUIREMENTS = + new Requirements(Requirements.NETWORK_TYPE_ANY, false, false); - private final ForegroundNotificationUpdater foregroundNotificationUpdater; + private final @Nullable ForegroundNotificationUpdater foregroundNotificationUpdater; private final @Nullable String channelId; private final @StringRes int channelName; @@ -86,18 +87,31 @@ public abstract class DownloadService extends Service { private DownloadManagerListener downloadManagerListener; private int lastStartId; private boolean startedInForeground; + private boolean taskRemoved; /** - * Creates a DownloadService with {@link #DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL}. + * Creates a DownloadService. * - * @param foregroundNotificationId The notification id for the foreground notification, must not - * be 0. + *

    If {@code foregroundNotificationId} is {@link #FOREGROUND_NOTIFICATION_ID_NONE} (value + * {@value #FOREGROUND_NOTIFICATION_ID_NONE}) then the service runs in the background. No + * foreground notification is displayed and {@link #getScheduler()} isn't called. + * + *

    If {@code foregroundNotificationId} isn't {@link #FOREGROUND_NOTIFICATION_ID_NONE} (value + * {@value #FOREGROUND_NOTIFICATION_ID_NONE}) the service runs in the foreground with {@link + * #DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL}. In that case {@link + * #getForegroundNotification(TaskState[])} should be overridden in the subclass. + * + * @param foregroundNotificationId The notification id for the foreground notification, or {@link + * #FOREGROUND_NOTIFICATION_ID_NONE} (value {@value #FOREGROUND_NOTIFICATION_ID_NONE}) */ protected DownloadService(int foregroundNotificationId) { this(foregroundNotificationId, DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL); } /** + * Creates a DownloadService which will run in the foreground. {@link + * #getForegroundNotification(TaskState[])} should be overridden in the subclass. + * * @param foregroundNotificationId The notification id for the foreground notification, must not * be 0. * @param foregroundNotificationUpdateInterval The maximum interval to update foreground @@ -113,6 +127,9 @@ public abstract class DownloadService extends Service { } /** + * Creates a DownloadService which will run in the foreground. {@link + * #getForegroundNotification(TaskState[])} should be overridden in the subclass. + * * @param foregroundNotificationId The notification id for the foreground notification. Must not * be 0. * @param foregroundNotificationUpdateInterval The maximum interval between updates to the @@ -130,8 +147,10 @@ public abstract class DownloadService extends Service { @Nullable String channelId, @StringRes int channelName) { foregroundNotificationUpdater = - new ForegroundNotificationUpdater( - foregroundNotificationId, foregroundNotificationUpdateInterval); + foregroundNotificationId == 0 + ? null + : new ForegroundNotificationUpdater( + foregroundNotificationId, foregroundNotificationUpdateInterval); this.channelId = channelId; this.channelName = channelName; } @@ -150,8 +169,7 @@ public abstract class DownloadService extends Service { Class clazz, DownloadAction downloadAction, boolean foreground) { - return new Intent(context, clazz) - .setAction(ACTION_ADD) + return getIntent(context, clazz, ACTION_ADD) .putExtra(KEY_DOWNLOAD_ACTION, downloadAction.toByteArray()) .putExtra(KEY_FOREGROUND, foreground); } @@ -160,9 +178,9 @@ public abstract class DownloadService extends Service { * Starts the service, adding an action to be executed. * * @param context A {@link Context}. - * @param clazz The concrete download service being targeted by the intent. + * @param clazz The concrete download service to be started. * @param downloadAction The action to be executed. - * @param foreground Whether this intent will be used to start the service in the foreground. + * @param foreground Whether the service is started in the foreground. */ public static void startWithAction( Context context, @@ -177,6 +195,32 @@ public abstract class DownloadService extends Service { } } + /** + * Starts the service without adding a new action. If there are any not finished actions and the + * requirements are met, the service resumes executing actions. Otherwise it stops immediately. + * + * @param context A {@link Context}. + * @param clazz The concrete download service to be started. + * @see #startForeground(Context, Class) + */ + public static void start(Context context, Class clazz) { + context.startService(getIntent(context, clazz, ACTION_INIT)); + } + + /** + * Starts the service in the foreground without adding a new action. If there are any not finished + * actions and the requirements are met, the service resumes executing actions. Otherwise it stops + * immediately. + * + * @param context A {@link Context}. + * @param clazz The concrete download service to be started. + * @see #start(Context, Class) + */ + public static void startForeground(Context context, Class clazz) { + Intent intent = getIntent(context, clazz, ACTION_INIT).putExtra(KEY_FOREGROUND, true); + Util.startForegroundService(context, intent); + } + @Override public void onCreate() { logd("onCreate"); @@ -187,33 +231,27 @@ public abstract class DownloadService extends Service { downloadManager = getDownloadManager(); downloadManagerListener = new DownloadManagerListener(); downloadManager.addListener(downloadManagerListener); - - RequirementsHelper requirementsHelper; - synchronized (requirementsHelpers) { - Class clazz = getClass(); - requirementsHelper = requirementsHelpers.get(clazz); - if (requirementsHelper == null) { - requirementsHelper = new RequirementsHelper(this, getRequirements(), getScheduler(), clazz); - requirementsHelpers.put(clazz, requirementsHelper); - } - } - requirementsHelper.start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { lastStartId = startId; + taskRemoved = false; String intentAction = null; if (intent != null) { intentAction = intent.getAction(); startedInForeground |= intent.getBooleanExtra(KEY_FOREGROUND, false) || ACTION_RESTART.equals(intentAction); } + // intentAction is null if the service is restarted or no action is specified. + if (intentAction == null) { + intentAction = ACTION_INIT; + } logd("onStartCommand action: " + intentAction + " startId: " + startId); switch (intentAction) { case ACTION_INIT: case ACTION_RESTART: - // Do nothing. The RequirementsWatcher will start downloads when possible. + // Do nothing. break; case ACTION_ADD: byte[] actionData = intent.getByteArrayExtra(KEY_DOWNLOAD_ACTION); @@ -227,35 +265,42 @@ public abstract class DownloadService extends Service { } } break; - case ACTION_STOP_DOWNLOADS: - downloadManager.stopDownloads(); - break; - case ACTION_START_DOWNLOADS: - downloadManager.startDownloads(); + case ACTION_RELOAD_REQUIREMENTS: + stopWatchingRequirements(); break; default: Log.e(TAG, "Ignoring unrecognized action: " + intentAction); break; } + + Requirements requirements = getRequirements(); + if (requirements.checkRequirements(this)) { + downloadManager.startDownloads(); + } else { + downloadManager.stopDownloads(); + } + maybeStartWatchingRequirements(requirements); + if (downloadManager.isIdle()) { stop(); } return START_STICKY; } + @Override + public void onTaskRemoved(Intent rootIntent) { + logd("onTaskRemoved rootIntent: " + rootIntent); + taskRemoved = true; + } + @Override public void onDestroy() { logd("onDestroy"); - foregroundNotificationUpdater.stopPeriodicUpdates(); - downloadManager.removeListener(downloadManagerListener); - if (downloadManager.getTaskCount() == 0) { - synchronized (requirementsHelpers) { - RequirementsHelper requirementsHelper = requirementsHelpers.remove(getClass()); - if (requirementsHelper != null) { - requirementsHelper.stop(); - } - } + if (foregroundNotificationUpdater != null) { + foregroundNotificationUpdater.stopPeriodicUpdates(); } + downloadManager.removeListener(downloadManagerListener); + maybeStopWatchingRequirements(); } @Nullable @@ -284,11 +329,13 @@ public abstract class DownloadService extends Service { * device has network connectivity. */ protected Requirements getRequirements() { - return new Requirements(Requirements.NETWORK_TYPE_ANY, false, false); + return DEFAULT_REQUIREMENTS; } /** - * Returns a notification to be displayed when this service running in the foreground. + * Should be overridden in the subclass if the service will be run in the foreground. + * + *

    Returns a notification to be displayed when this service running in the foreground. * *

    This method is called when there is a task state change and periodically while there are * active tasks. The periodic update interval can be set using {@link #DownloadService(int, @@ -301,7 +348,11 @@ public abstract class DownloadService extends Service { * @param taskStates The states of all current tasks. * @return The foreground notification to display. */ - protected abstract Notification getForegroundNotification(TaskState[] taskStates); + protected Notification getForegroundNotification(TaskState[] taskStates) { + throw new IllegalStateException( + getClass().getName() + + " is started in the foreground but getForegroundNotification() is not implemented."); + } /** * Called when the state of a task changes. @@ -312,14 +363,50 @@ public abstract class DownloadService extends Service { // Do nothing. } - private void stop() { - foregroundNotificationUpdater.stopPeriodicUpdates(); - // Make sure startForeground is called before stopping. Workaround for [Internal: b/69424260]. - if (startedInForeground && Util.SDK_INT >= 26) { - foregroundNotificationUpdater.showNotificationIfNotAlready(); + private void maybeStartWatchingRequirements(Requirements requirements) { + if (downloadManager.getDownloadCount() == 0) { + return; + } + Class clazz = getClass(); + RequirementsHelper requirementsHelper = requirementsHelpers.get(clazz); + if (requirementsHelper == null) { + requirementsHelper = new RequirementsHelper(this, requirements, getScheduler(), clazz); + requirementsHelpers.put(clazz, requirementsHelper); + requirementsHelper.start(); + logd("started watching requirements"); + } + } + + private void maybeStopWatchingRequirements() { + if (downloadManager.getDownloadCount() > 0) { + return; + } + stopWatchingRequirements(); + } + + private void stopWatchingRequirements() { + RequirementsHelper requirementsHelper = requirementsHelpers.remove(getClass()); + if (requirementsHelper != null) { + requirementsHelper.stop(); + logd("stopped watching requirements"); + } + } + + private void stop() { + if (foregroundNotificationUpdater != null) { + foregroundNotificationUpdater.stopPeriodicUpdates(); + // Make sure startForeground is called before stopping. Workaround for [Internal: b/69424260]. + if (startedInForeground && Util.SDK_INT >= 26) { + foregroundNotificationUpdater.showNotificationIfNotAlready(); + } + } + if (Util.SDK_INT < 28 && taskRemoved) { // See [Internal: b/74248644]. + stopSelf(); + logd("stopSelf()"); + } else { + boolean stopSelfResult = stopSelfResult(lastStartId); + logd("stopSelf(" + lastStartId + ") result: " + stopSelfResult); } - boolean stopSelfResult = stopSelfResult(lastStartId); - logd("stopSelf(" + lastStartId + ") result: " + stopSelfResult); } private void logd(String message) { @@ -328,19 +415,26 @@ public abstract class DownloadService extends Service { } } + private static Intent getIntent( + Context context, Class clazz, String action) { + return new Intent(context, clazz).setAction(action); + } + private final class DownloadManagerListener implements DownloadManager.Listener { @Override public void onInitialized(DownloadManager downloadManager) { - // Do nothing. + maybeStartWatchingRequirements(getRequirements()); } @Override public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) { DownloadService.this.onTaskStateChanged(taskState); - if (taskState.state == TaskState.STATE_STARTED) { - foregroundNotificationUpdater.startPeriodicUpdates(); - } else { - foregroundNotificationUpdater.update(); + if (foregroundNotificationUpdater != null) { + if (taskState.state == TaskState.STATE_STARTED) { + foregroundNotificationUpdater.startPeriodicUpdates(); + } else { + foregroundNotificationUpdater.update(); + } } } @@ -430,7 +524,12 @@ public abstract class DownloadService extends Service { @Override public void requirementsMet(RequirementsWatcher requirementsWatcher) { - startServiceWithAction(DownloadService.ACTION_START_DOWNLOADS); + try { + notifyService(); + } catch (Exception e) { + /* If we can't notify the service, don't stop the scheduler. */ + return; + } if (scheduler != null) { scheduler.cancel(); } @@ -438,7 +537,11 @@ public abstract class DownloadService extends Service { @Override public void requirementsNotMet(RequirementsWatcher requirementsWatcher) { - startServiceWithAction(DownloadService.ACTION_STOP_DOWNLOADS); + try { + notifyService(); + } catch (Exception e) { + /* Do nothing. The service isn't running anyway. */ + } if (scheduler != null) { String servicePackage = context.getPackageName(); boolean success = scheduler.schedule(requirements, servicePackage, ACTION_RESTART); @@ -448,10 +551,14 @@ public abstract class DownloadService extends Service { } } - private void startServiceWithAction(String action) { - Intent intent = - new Intent(context, serviceClass).setAction(action).putExtra(KEY_FOREGROUND, true); - Util.startForegroundService(context, intent); + private void notifyService() throws Exception { + Intent intent = getIntent(context, serviceClass, DownloadService.ACTION_INIT); + try { + context.startService(intent); + } catch (IllegalStateException e) { + /* startService will fail if the app is in the background and the service isn't running. */ + throw new Exception(e); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/Downloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/Downloader.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/Downloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/Downloader.java index 1c50d10eb..10523d6bc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/Downloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/Downloader.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloaderConstructorHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloaderConstructorHelper.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloaderConstructorHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloaderConstructorHelper.java index 03d6280ec..18387b9d9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/DownloaderConstructorHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/DownloaderConstructorHelper.java @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSink; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSource.Factory; -import org.telegram.messenger.exoplayer2.upstream.DummyDataSource; -import org.telegram.messenger.exoplayer2.upstream.FileDataSource; -import org.telegram.messenger.exoplayer2.upstream.PriorityDataSource; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheDataSink; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheDataSource; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSource.Factory; +import com.google.android.exoplayer2.upstream.DummyDataSource; +import com.google.android.exoplayer2.upstream.FileDataSource; +import com.google.android.exoplayer2.upstream.PriorityDataSource; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.upstream.cache.CacheDataSink; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.PriorityTaskManager; /** A helper class that holds necessary parameters for {@link Downloader} construction. */ public final class DownloaderConstructorHelper { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilterableManifest.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilterableManifest.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilterableManifest.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilterableManifest.java index 6009bdfcf..e688b7216 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilterableManifest.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilterableManifest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import java.util.List; @@ -22,9 +22,8 @@ import java.util.List; * keys. * * @param The manifest type. - * @param The stream key type. */ -public interface FilterableManifest { +public interface FilterableManifest { /** * Returns a copy of the manifest including only the streams specified by the given keys. If the @@ -33,5 +32,5 @@ public interface FilterableManifest { * @param streamKeys A non-empty list of stream keys. * @return The filtered manifest. */ - T copy(List streamKeys); + T copy(List streamKeys); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilteringManifestParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilteringManifestParser.java similarity index 64% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilteringManifestParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilteringManifestParser.java index d8bfe4cf6..c32cdf712 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/FilteringManifestParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/FilteringManifestParser.java @@ -13,33 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable.Parser; +import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser; import java.io.IOException; import java.io.InputStream; import java.util.List; -/** A manifest parser that includes only the tracks identified by the given track keys. */ -public final class FilteringManifestParser, K> - implements Parser { +/** A manifest parser that includes only the streams identified by the given stream keys. */ +public final class FilteringManifestParser> implements Parser { private final Parser parser; - private final List trackKeys; + private final List streamKeys; /** * @param parser A parser for the manifest that will be filtered. - * @param trackKeys The track keys. If null or empty then filtering will not occur. + * @param streamKeys The stream keys. If null or empty then filtering will not occur. */ - public FilteringManifestParser(Parser parser, List trackKeys) { + public FilteringManifestParser(Parser parser, List streamKeys) { this.parser = parser; - this.trackKeys = trackKeys; + this.streamKeys = streamKeys; } @Override public T parse(Uri uri, InputStream inputStream) throws IOException { T manifest = parser.parse(uri, inputStream); - return trackKeys == null || trackKeys.isEmpty() ? manifest : manifest.copy(trackKeys); + return streamKeys == null || streamKeys.isEmpty() ? manifest : manifest.copy(streamKeys); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java similarity index 69% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadAction.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java index 967687c10..7ced2fa41 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadAction.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.upstream.cache.CacheUtil; +import com.google.android.exoplayer2.util.Util; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -44,7 +44,33 @@ public final class ProgressiveDownloadAction extends DownloadAction { } }; - public final @Nullable String customCacheKey; + private final @Nullable String customCacheKey; + + /** + * Creates a progressive stream download action. + * + * @param uri Uri of the data to be downloaded. + * @param data Optional custom data for this action. + * @param customCacheKey A custom key that uniquely identifies the original stream. If not null it + * is used for cache indexing. + */ + public static ProgressiveDownloadAction createDownloadAction( + Uri uri, @Nullable byte[] data, @Nullable String customCacheKey) { + return new ProgressiveDownloadAction(uri, /* isRemoveAction= */ false, data, customCacheKey); + } + + /** + * Creates a progressive stream remove action. + * + * @param uri Uri of the data to be removed. + * @param data Optional custom data for this action. + * @param customCacheKey A custom key that uniquely identifies the original stream. If not null it + * is used for cache indexing. + */ + public static ProgressiveDownloadAction createRemoveAction( + Uri uri, @Nullable byte[] data, @Nullable String customCacheKey) { + return new ProgressiveDownloadAction(uri, /* isRemoveAction= */ true, data, customCacheKey); + } /** * @param uri Uri of the data to be downloaded. @@ -52,7 +78,10 @@ public final class ProgressiveDownloadAction extends DownloadAction { * @param data Optional custom data for this action. * @param customCacheKey A custom key that uniquely identifies the original stream. If not null it * is used for cache indexing. + * @deprecated Use {@link #createDownloadAction(Uri, byte[], String)} or {@link + * #createRemoveAction(Uri, byte[], String)}. */ + @Deprecated public ProgressiveDownloadAction( Uri uri, boolean isRemoveAction, @Nullable byte[] data, @Nullable String customCacheKey) { super(TYPE, VERSION, uri, isRemoveAction, data); @@ -60,7 +89,7 @@ public final class ProgressiveDownloadAction extends DownloadAction { } @Override - protected ProgressiveDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { + public ProgressiveDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { return new ProgressiveDownloader(uri, customCacheKey, constructorHelper); } @@ -105,4 +134,5 @@ public final class ProgressiveDownloadAction extends DownloadAction { private String getCacheKey() { return customCacheKey != null ? customCacheKey : CacheUtil.generateKey(uri); } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadHelper.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadHelper.java index ac7eb7e47..473209803 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloadHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadHelper.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.TrackGroupArray; import java.util.List; /** A {@link DownloadHelper} for progressive streams. */ @@ -51,12 +51,13 @@ public final class ProgressiveDownloadHelper extends DownloadHelper { } @Override - public DownloadAction getDownloadAction(@Nullable byte[] data, List trackKeys) { - return new ProgressiveDownloadAction(uri, false, data, customCacheKey); + public ProgressiveDownloadAction getDownloadAction( + @Nullable byte[] data, List trackKeys) { + return ProgressiveDownloadAction.createDownloadAction(uri, data, customCacheKey); } @Override - public DownloadAction getRemoveAction(@Nullable byte[] data) { - return new ProgressiveDownloadAction(uri, true, data, customCacheKey); + public ProgressiveDownloadAction getRemoveAction(@Nullable byte[] data) { + return ProgressiveDownloadAction.createRemoveAction(uri, data, customCacheKey); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java index 0bf4510ad..8c80a23d6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/ProgressiveDownloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheDataSource; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheUtil; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheUtil.CachingCounters; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource; +import com.google.android.exoplayer2.upstream.cache.CacheUtil; +import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; +import com.google.android.exoplayer2.util.PriorityTaskManager; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java similarity index 74% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloadAction.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java index 525dbfe57..403b4e797 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloadAction.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -25,19 +25,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -/** - * {@link DownloadAction} for {@link SegmentDownloader}s. - * - * @param The type of the representation key object. - */ -public abstract class SegmentDownloadAction> extends DownloadAction { +/** {@link DownloadAction} for {@link SegmentDownloader}s. */ +public abstract class SegmentDownloadAction extends DownloadAction { - /** - * Base class for {@link SegmentDownloadAction} {@link Deserializer}s. - * - * @param The type of the representation key object. - */ - protected abstract static class SegmentDownloadActionDeserializer extends Deserializer { + /** Base class for {@link SegmentDownloadAction} {@link Deserializer}s. */ + protected abstract static class SegmentDownloadActionDeserializer extends Deserializer { public SegmentDownloadActionDeserializer(String type, int version) { super(type, version); @@ -52,22 +44,27 @@ public abstract class SegmentDownloadAction> extends Dow byte[] data = new byte[dataLength]; input.readFully(data); int keyCount = input.readInt(); - List keys = new ArrayList<>(); + List keys = new ArrayList<>(); for (int i = 0; i < keyCount; i++) { - keys.add(readKey(input)); + keys.add(readKey(version, input)); } return createDownloadAction(uri, isRemoveAction, data, keys); } /** Deserializes a key from the {@code input}. */ - protected abstract K readKey(DataInputStream input) throws IOException; + protected StreamKey readKey(int version, DataInputStream input) throws IOException { + int periodIndex = input.readInt(); + int groupIndex = input.readInt(); + int trackIndex = input.readInt(); + return new StreamKey(periodIndex, groupIndex, trackIndex); + } /** Returns a {@link DownloadAction}. */ protected abstract DownloadAction createDownloadAction( - Uri manifestUri, boolean isRemoveAction, byte[] data, List keys); + Uri manifestUri, boolean isRemoveAction, byte[] data, List keys); } - public final List keys; + public final List keys; /** * @param type The type of the action. @@ -84,18 +81,23 @@ public abstract class SegmentDownloadAction> extends Dow Uri uri, boolean isRemoveAction, @Nullable byte[] data, - List keys) { + List keys) { super(type, version, uri, isRemoveAction, data); if (isRemoveAction) { Assertions.checkArgument(keys.isEmpty()); this.keys = Collections.emptyList(); } else { - ArrayList mutableKeys = new ArrayList<>(keys); + ArrayList mutableKeys = new ArrayList<>(keys); Collections.sort(mutableKeys); this.keys = Collections.unmodifiableList(mutableKeys); } } + @Override + public List getKeys() { + return keys; + } + @Override public final void writeToStream(DataOutputStream output) throws IOException { output.writeUTF(uri.toString()); @@ -108,9 +110,6 @@ public abstract class SegmentDownloadAction> extends Dow } } - /** Serializes the {@code key} into the {@code output}. */ - protected abstract void writeKey(DataOutputStream output, K key) throws IOException; - @Override public boolean equals(@Nullable Object o) { if (this == o) { @@ -119,7 +118,7 @@ public abstract class SegmentDownloadAction> extends Dow if (!super.equals(o)) { return false; } - SegmentDownloadAction that = (SegmentDownloadAction) o; + SegmentDownloadAction that = (SegmentDownloadAction) o; return keys.equals(that.keys); } @@ -130,4 +129,10 @@ public abstract class SegmentDownloadAction> extends Dow return result; } + /** Serializes the {@code key} into the {@code output}. */ + private void writeKey(DataOutputStream output, StreamKey key) throws IOException { + output.writeInt(key.periodIndex); + output.writeInt(key.groupIndex); + output.writeInt(key.trackIndex); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java index 6ced56651..9aa7afd7c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/SegmentDownloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; import android.net.Uri; import android.support.annotation.NonNull; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheDataSource; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheUtil; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheUtil.CachingCounters; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource; +import com.google.android.exoplayer2.upstream.cache.CacheUtil; +import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; +import com.google.android.exoplayer2.util.PriorityTaskManager; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -35,10 +35,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * Base class for multi segment stream downloaders. * * @param The type of the manifest object. - * @param The type of the streams key object. */ -public abstract class SegmentDownloader, K> - implements Downloader { +public abstract class SegmentDownloader> implements Downloader { /** Smallest unit of content to be downloaded. */ protected static class Segment implements Comparable { @@ -68,7 +66,7 @@ public abstract class SegmentDownloader, K> private final Cache cache; private final CacheDataSource dataSource; private final CacheDataSource offlineDataSource; - private final ArrayList streamKeys; + private final ArrayList streamKeys; private final AtomicBoolean isCanceled; private volatile int totalSegments; @@ -82,7 +80,7 @@ public abstract class SegmentDownloader, K> * @param constructorHelper A {@link DownloaderConstructorHelper} instance. */ public SegmentDownloader( - Uri manifestUri, List streamKeys, DownloaderConstructorHelper constructorHelper) { + Uri manifestUri, List streamKeys, DownloaderConstructorHelper constructorHelper) { this.manifestUri = manifestUri; this.streamKeys = new ArrayList<>(streamKeys); this.cache = constructorHelper.getCache(); @@ -201,6 +199,8 @@ public abstract class SegmentDownloader, K> throws InterruptedException, IOException; /** Initializes the download, returning a list of {@link Segment}s that need to be downloaded. */ + // Writes to downloadedSegments and downloadedBytes are safe. See the comment on download(). + @SuppressWarnings("NonAtomicVolatileUpdate") private List initDownload() throws IOException, InterruptedException { M manifest = getManifest(dataSource, manifestUri); if (!streamKeys.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/StreamKey.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/StreamKey.java similarity index 50% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/StreamKey.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/StreamKey.java index 5abbf3802..838073cd9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/StreamKey.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/StreamKey.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,25 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest; +package com.google.android.exoplayer2.offline; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -/** Uniquely identifies a track in a {@link SsManifest}. */ +/** + * Identifies a given track by the index of the containing period, the index of the containing group + * within the period, and the index of the track within the group. + */ public final class StreamKey implements Comparable { - public final int streamElementIndex; + /** The period index. */ + public final int periodIndex; + /** The group index. */ + public final int groupIndex; + /** The track index. */ public final int trackIndex; - public StreamKey(int streamElementIndex, int trackIndex) { - this.streamElementIndex = streamElementIndex; + /** + * @param groupIndex The group index. + * @param trackIndex The track index. + */ + public StreamKey(int groupIndex, int trackIndex) { + this(0, groupIndex, trackIndex); + } + + /** + * @param periodIndex The period index. + * @param groupIndex The group index. + * @param trackIndex The track index. + */ + public StreamKey(int periodIndex, int groupIndex, int trackIndex) { + this.periodIndex = periodIndex; + this.groupIndex = groupIndex; this.trackIndex = trackIndex; } @Override public String toString() { - return streamElementIndex + "." + trackIndex; + return periodIndex + "." + groupIndex + "." + trackIndex; } @Override @@ -44,12 +65,15 @@ public final class StreamKey implements Comparable { } StreamKey that = (StreamKey) o; - return streamElementIndex == that.streamElementIndex && trackIndex == that.trackIndex; + return periodIndex == that.periodIndex + && groupIndex == that.groupIndex + && trackIndex == that.trackIndex; } @Override public int hashCode() { - int result = streamElementIndex; + int result = periodIndex; + result = 31 * result + groupIndex; result = 31 * result + trackIndex; return result; } @@ -58,9 +82,12 @@ public final class StreamKey implements Comparable { @Override public int compareTo(@NonNull StreamKey o) { - int result = streamElementIndex - o.streamElementIndex; + int result = periodIndex - o.periodIndex; if (result == 0) { - result = trackIndex - o.trackIndex; + result = groupIndex - o.groupIndex; + if (result == 0) { + result = trackIndex - o.trackIndex; + } } return result; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/TrackKey.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/TrackKey.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/TrackKey.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/TrackKey.java index 7c35eaa10..f6a411c3a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/offline/TrackKey.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/offline/TrackKey.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.offline; +package com.google.android.exoplayer2.offline; /** * Identifies a given track by the index of the containing period, the index of the containing group diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/PlatformScheduler.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/PlatformScheduler.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/PlatformScheduler.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/PlatformScheduler.java index bb454682c..b3737eb8b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/PlatformScheduler.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/PlatformScheduler.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.scheduler; +package com.google.android.exoplayer2.scheduler; import android.annotation.TargetApi; import android.app.job.JobInfo; @@ -26,7 +26,7 @@ import android.content.Intent; import android.os.PersistableBundle; import android.support.annotation.RequiresPermission; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** * A {@link Scheduler} that uses {@link JobScheduler}. To use this scheduler, you must add {@link @@ -35,7 +35,7 @@ import org.telegram.messenger.exoplayer2.util.Util; *

    {@literal
      * 
      *
    - * 
      * }
    diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Requirements.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Requirements.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java index 4fbaee4a7..30b07da3e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Requirements.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.scheduler; +package com.google.android.exoplayer2.scheduler; import android.content.Context; import android.content.Intent; @@ -26,7 +26,7 @@ import android.os.BatteryManager; import android.os.PowerManager; import android.support.annotation.IntDef; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/RequirementsWatcher.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/RequirementsWatcher.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java index 21df04863..acd88182f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/RequirementsWatcher.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.scheduler; +package com.google.android.exoplayer2.scheduler; import android.annotation.TargetApi; import android.content.BroadcastReceiver; @@ -29,8 +29,8 @@ import android.os.Looper; import android.os.PowerManager; import android.support.annotation.RequiresApi; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; /** * Watches whether the {@link Requirements} are met and notifies the {@link Listener} on changes. @@ -87,7 +87,7 @@ public final class RequirementsWatcher { public void start() { Assertions.checkNotNull(Looper.myLooper()); - checkRequirements(true); + requirementsWereMet = requirements.checkRequirements(context); IntentFilter filter = new IntentFilter(); if (requirements.getRequiredNetworkType() != Requirements.NETWORK_TYPE_NONE) { @@ -158,13 +158,11 @@ public final class RequirementsWatcher { } } - private void checkRequirements(boolean force) { + private void checkRequirements() { boolean requirementsAreMet = requirements.checkRequirements(context); - if (!force) { - if (requirementsAreMet == requirementsWereMet) { - logd("requirementsAreMet is still " + requirementsAreMet); - return; - } + if (requirementsAreMet == requirementsWereMet) { + logd("requirementsAreMet is still " + requirementsAreMet); + return; } requirementsWereMet = requirementsAreMet; if (requirementsAreMet) { @@ -187,7 +185,7 @@ public final class RequirementsWatcher { public void onReceive(Context context, Intent intent) { if (!isInitialStickyBroadcast()) { logd(RequirementsWatcher.this + " received " + intent.getAction()); - checkRequirements(false); + checkRequirements(); } } } @@ -198,14 +196,14 @@ public final class RequirementsWatcher { public void onAvailable(Network network) { super.onAvailable(network); logd(RequirementsWatcher.this + " NetworkCallback.onAvailable"); - checkRequirements(false); + checkRequirements(); } @Override public void onLost(Network network) { super.onLost(network); logd(RequirementsWatcher.this + " NetworkCallback.onLost"); - checkRequirements(false); + checkRequirements(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Scheduler.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Scheduler.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Scheduler.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Scheduler.java index fa548bf9e..1b225d9a4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/scheduler/Scheduler.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/scheduler/Scheduler.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.scheduler; +package com.google.android.exoplayer2.scheduler; import android.app.Notification; import android.app.Service; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AbstractConcatenatedTimeline.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AbstractConcatenatedTimeline.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index ffce911a4..305a249e4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Timeline; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Timeline; /** * Abstract base class for the concatenation of one or more {@link Timeline}s. @@ -168,6 +168,19 @@ import org.telegram.messenger.exoplayer2.Timeline; return window; } + @Override + public final Period getPeriodByUid(Object uid, Period period) { + Pair childUidAndPeriodUid = (Pair) uid; + Object childUid = childUidAndPeriodUid.first; + Object periodUid = childUidAndPeriodUid.second; + int childIndex = getChildIndexByChildUid(childUid); + int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex); + getTimelineByChildIndex(childIndex).getPeriodByUid(periodUid, period); + period.windowIndex += firstWindowIndexInChild; + period.uid = uid; + return period; + } + @Override public final Period getPeriod(int periodIndex, Period period, boolean setIds) { int childIndex = getChildIndexByPeriodIndex(periodIndex); @@ -199,6 +212,15 @@ import org.telegram.messenger.exoplayer2.Timeline; : getFirstPeriodIndexByChildIndex(childIndex) + periodIndexInChild; } + @Override + public final Object getUidOfPeriod(int periodIndex) { + int childIndex = getChildIndexByPeriodIndex(periodIndex); + int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex); + Object periodUidInChild = + getTimelineByChildIndex(childIndex).getUidOfPeriod(periodIndex - firstPeriodIndexInChild); + return Pair.create(getChildUidByChildIndex(childIndex), periodUidInChild); + } + /** * Returns the index of the child timeline containing the given period index. * diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AdaptiveMediaSourceEventListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AdaptiveMediaSourceEventListener.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AdaptiveMediaSourceEventListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AdaptiveMediaSourceEventListener.java index b25945076..ccc3beac5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/AdaptiveMediaSourceEventListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/AdaptiveMediaSourceEventListener.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; /** * Interface for callbacks to be notified of {@link MediaSource} events. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BaseMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BaseMediaSource.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BaseMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BaseMediaSource.java index 316894554..2feac2978 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BaseMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BaseMediaSource.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.util.ArrayList; /** @@ -34,9 +35,9 @@ public abstract class BaseMediaSource implements MediaSource { private final ArrayList sourceInfoListeners; private final MediaSourceEventListener.EventDispatcher eventDispatcher; - private ExoPlayer player; - private Timeline timeline; - private Object manifest; + private @Nullable ExoPlayer player; + private @Nullable Timeline timeline; + private @Nullable Object manifest; public BaseMediaSource() { sourceInfoListeners = new ArrayList<>(/* initialCapacity= */ 1); @@ -51,12 +52,17 @@ public abstract class BaseMediaSource implements MediaSource { * @param isTopLevelSource Whether this source has been passed directly to {@link * ExoPlayer#prepare(MediaSource)} or {@link ExoPlayer#prepare(MediaSource, boolean, * boolean)}. + * @param mediaTransferListener The transfer listener which should be informed of any media data + * transfers. May be null if no listener is available. Note that this listener should usually + * be only informed of transfers related to the media loads and not of auxiliary loads for + * manifests and other data. */ - protected abstract void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource); + protected abstract void prepareSourceInternal( + ExoPlayer player, boolean isTopLevelSource, @Nullable TransferListener mediaTransferListener); /** * Releases the source. This method is called exactly once after each call to {@link - * #prepareSourceInternal(ExoPlayer, boolean)}. + * #prepareSourceInternal(ExoPlayer, boolean, TransferListener)}. */ protected abstract void releaseSourceInternal(); @@ -130,11 +136,20 @@ public abstract class BaseMediaSource implements MediaSource { @Override public final void prepareSource( ExoPlayer player, boolean isTopLevelSource, SourceInfoRefreshListener listener) { + prepareSource(player, isTopLevelSource, listener, /* mediaTransferListener= */ null); + } + + @Override + public final void prepareSource( + ExoPlayer player, + boolean isTopLevelSource, + SourceInfoRefreshListener listener, + @Nullable TransferListener mediaTransferListener) { Assertions.checkArgument(this.player == null || this.player == player); sourceInfoListeners.add(listener); if (this.player == null) { this.player = player; - prepareSourceInternal(player, isTopLevelSource); + prepareSourceInternal(player, isTopLevelSource, mediaTransferListener); } else if (timeline != null) { listener.onSourceInfoRefreshed(/* source= */ this, timeline, manifest); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BehindLiveWindowException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BehindLiveWindowException.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BehindLiveWindowException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BehindLiveWindowException.java index 2127a202b..8e0441dfc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/BehindLiveWindowException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/BehindLiveWindowException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index f8a14adc1..c07805311 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index 357ded538..f49485650 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ClippingMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -211,8 +212,11 @@ public final class ClippingMediaSource extends CompositeMediaSource { } @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { - super.prepareSourceInternal(player, isTopLevelSource); + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener); prepareChildSource(/* id= */ null, mediaSource); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeMediaSource.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeMediaSource.java index 7c936aa60..2ef518622 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeMediaSource.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Handler; import android.support.annotation.CallSuper; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.HashMap; @@ -35,8 +35,9 @@ public abstract class CompositeMediaSource extends BaseMediaSource { private final HashMap childSources; - private ExoPlayer player; - private Handler eventHandler; + private @Nullable ExoPlayer player; + private @Nullable Handler eventHandler; + private @Nullable TransferListener mediaTransferListener; /** Create composite media source without child sources. */ protected CompositeMediaSource() { @@ -45,8 +46,12 @@ public abstract class CompositeMediaSource extends BaseMediaSource { @Override @CallSuper - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { this.player = player; + this.mediaTransferListener = mediaTransferListener; eventHandler = new Handler(); } @@ -78,7 +83,7 @@ public abstract class CompositeMediaSource extends BaseMediaSource { * @param manifest The manifest of the child source. */ protected abstract void onChildSourceInfoRefreshed( - @Nullable T id, MediaSource mediaSource, Timeline timeline, @Nullable Object manifest); + T id, MediaSource mediaSource, Timeline timeline, @Nullable Object manifest); /** * Prepares a child source. @@ -93,7 +98,7 @@ public abstract class CompositeMediaSource extends BaseMediaSource { * @param id A unique id to identify the child source preparation. Null is allowed as an id. * @param mediaSource The child {@link MediaSource}. */ - protected final void prepareChildSource(@Nullable final T id, MediaSource mediaSource) { + protected final void prepareChildSource(final T id, MediaSource mediaSource) { Assertions.checkArgument(!childSources.containsKey(id)); SourceInfoRefreshListener sourceListener = new SourceInfoRefreshListener() { @@ -105,8 +110,12 @@ public abstract class CompositeMediaSource extends BaseMediaSource { }; MediaSourceEventListener eventListener = new ForwardingEventListener(id); childSources.put(id, new MediaSourceAndListener(mediaSource, sourceListener, eventListener)); - mediaSource.addEventListener(eventHandler, eventListener); - mediaSource.prepareSource(player, /* isTopLevelSource= */ false, sourceListener); + mediaSource.addEventListener(Assertions.checkNotNull(eventHandler), eventListener); + mediaSource.prepareSource( + Assertions.checkNotNull(player), + /* isTopLevelSource= */ false, + sourceListener, + mediaTransferListener); } /** @@ -114,8 +123,8 @@ public abstract class CompositeMediaSource extends BaseMediaSource { * * @param id The unique id used to prepare the child source. */ - protected final void releaseChildSource(@Nullable T id) { - MediaSourceAndListener removedChild = childSources.remove(id); + protected final void releaseChildSource(T id) { + MediaSourceAndListener removedChild = Assertions.checkNotNull(childSources.remove(id)); removedChild.mediaSource.releaseSource(removedChild.listener); removedChild.mediaSource.removeEventListener(removedChild.eventListener); } @@ -128,7 +137,7 @@ public abstract class CompositeMediaSource extends BaseMediaSource { * @param windowIndex A window index of the child source. * @return The corresponding window index in the composite source. */ - protected int getWindowIndexForChildWindowIndex(@Nullable T id, int windowIndex) { + protected int getWindowIndexForChildWindowIndex(T id, int windowIndex) { return windowIndex; } @@ -143,7 +152,7 @@ public abstract class CompositeMediaSource extends BaseMediaSource { * corresponding media period id can be determined. */ protected @Nullable MediaPeriodId getMediaPeriodIdForChildMediaPeriodId( - @Nullable T id, MediaPeriodId mediaPeriodId) { + T id, MediaPeriodId mediaPeriodId) { return mediaPeriodId; } @@ -177,10 +186,10 @@ public abstract class CompositeMediaSource extends BaseMediaSource { private final class ForwardingEventListener implements MediaSourceEventListener { - private final @Nullable T id; + private final T id; private EventDispatcher eventDispatcher; - public ForwardingEventListener(@Nullable T id) { + public ForwardingEventListener(T id) { this.eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null); this.id = id; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java index a9ed5774c..c41933b48 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** * A {@link SequenceableLoader} that encapsulates multiple other {@link SequenceableLoader}s. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoaderFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoaderFactory.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoaderFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoaderFactory.java index 955a5a43c..b4a266fee 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/CompositeSequenceableLoaderFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoaderFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; /** * A factory to create composite {@link SequenceableLoader}s. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ConcatenatingMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ConcatenatingMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 1c5308539..20df2a8ab 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ConcatenatingMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -13,27 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Handler; -import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.SparseIntArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.PlayerMessage; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.ConcatenatingMediaSource.MediaSourceHolder; -import org.telegram.messenger.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.PlayerMessage; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ConcatenatingMediaSource.MediaSourceHolder; +import com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -61,42 +61,18 @@ public class ConcatenatingMediaSource extends CompositeMediaSource mediaSourceHolders; private final MediaSourceHolder query; private final Map mediaSourceByMediaPeriod; - private final List pendingOnCompletionActions; + private final List pendingOnCompletionActions; private final boolean isAtomic; + private final boolean useLazyPreparation; private final Timeline.Window window; - private ExoPlayer player; + private @Nullable ExoPlayer player; + private @Nullable Handler playerApplicationHandler; private boolean listenerNotificationScheduled; private ShuffleOrder shuffleOrder; private int windowCount; private int periodCount; - /** Creates a new concatenating media source. */ - public ConcatenatingMediaSource() { - this(/* isAtomic= */ false, new DefaultShuffleOrder(0)); - } - - /** - * Creates a new concatenating media source. - * - * @param isAtomic Whether the concatenating media source will be treated as atomic, i.e., treated - * as a single item for repeating and shuffling. - */ - public ConcatenatingMediaSource(boolean isAtomic) { - this(isAtomic, new DefaultShuffleOrder(0)); - } - - /** - * Creates a new concatenating media source with a custom shuffle order. - * - * @param isAtomic Whether the concatenating media source will be treated as atomic, i.e., treated - * as a single item for repeating and shuffling. - * @param shuffleOrder The {@link ShuffleOrder} to use when shuffling the child media sources. - */ - public ConcatenatingMediaSource(boolean isAtomic, ShuffleOrder shuffleOrder) { - this(isAtomic, shuffleOrder, new MediaSource[0]); - } - /** * @param mediaSources The {@link MediaSource}s to concatenate. It is valid for the same * {@link MediaSource} instance to be present more than once in the array. @@ -124,6 +100,25 @@ public class ConcatenatingMediaSource extends CompositeMediaSource(); this.query = new MediaSourceHolder(/* mediaSource= */ null); this.isAtomic = isAtomic; + this.useLazyPreparation = useLazyPreparation; window = new Timeline.Window(); addMediaSources(Arrays.asList(mediaSources)); } @@ -293,7 +289,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource(index, null, actionOnCompletion)) + .setPayload(new MessageData(index, null, actionOnCompletion)) .send(); } else if (actionOnCompletion != null) { actionOnCompletion.run(); @@ -354,11 +350,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource addMessage = (MessageData) message; @@ -492,15 +496,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource actionsOnCompletion = ((List) message); + List actionsOnCompletion = ((List) message); + Handler handler = Assertions.checkNotNull(playerApplicationHandler); for (int i = 0; i < actionsOnCompletion.size(); i++) { - actionsOnCompletion.get(i).dispatchEvent(); + handler.post(actionsOnCompletion.get(i)); } break; default: @@ -508,9 +513,9 @@ public class ConcatenatingMediaSource extends CompositeMediaSource actionsOnCompletion = + List actionsOnCompletion = pendingOnCompletionActions.isEmpty() - ? Collections.emptyList() + ? Collections.emptyList() : new ArrayList<>(pendingOnCompletionActions); pendingOnCompletionActions.clear(); refreshSourceInfo( @@ -530,7 +535,11 @@ public class ConcatenatingMediaSource extends CompositeMediaSource { public final MediaSource mediaSource; - public final int uid; + public final Object uid; public DeferredTimeline timeline; public int childIndex; public int firstWindowIndexInChild; public int firstPeriodIndexInChild; + public boolean hasStartedPreparing; public boolean isPrepared; public boolean isRemoved; public List activeMediaPeriods; public MediaSourceHolder(MediaSource mediaSource) { this.mediaSource = mediaSource; - this.uid = System.identityHashCode(this); this.timeline = new DeferredTimeline(); this.activeMediaPeriods = new ArrayList<>(); + this.uid = new Object(); } public void reset(int childIndex, int firstWindowIndexInChild, int firstPeriodIndexInChild) { this.childIndex = childIndex; this.firstWindowIndexInChild = firstWindowIndexInChild; this.firstPeriodIndexInChild = firstPeriodIndexInChild; + this.hasStartedPreparing = false; this.isPrepared = false; this.isRemoved = false; this.activeMediaPeriods.clear(); @@ -688,34 +705,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource { public final int index; public final T customData; - public final @Nullable EventDispatcher actionOnCompletion; + public final @Nullable Runnable actionOnCompletion; public MessageData(int index, T customData, @Nullable Runnable actionOnCompletion) { this.index = index; - this.actionOnCompletion = - actionOnCompletion != null ? new EventDispatcher(actionOnCompletion) : null; + this.actionOnCompletion = actionOnCompletion; this.customData = customData; } } @@ -728,8 +727,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource childIndexByUid; public ConcatenatedTimeline( Collection mediaSourceHolders, @@ -744,8 +743,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource(); int index = 0; for (MediaSourceHolder mediaSourceHolder : mediaSourceHolders) { timelines[index] = mediaSourceHolder.timeline; @@ -768,11 +767,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource 0 - ? timeline.getPeriod(0, period, true).uid + replacedId == DUMMY_ID && timeline.getPeriodCount() > 0 + ? timeline.getUidOfPeriod(0) : replacedId); } @@ -853,6 +847,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource 0 ? C.TIME_UNSET : 0, + /* defaultPositionUs= */ 0, /* durationUs= */ C.TIME_UNSET, /* firstPeriodIndex= */ 0, /* lastPeriodIndex= */ 0, @@ -889,8 +888,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource extractedSamplesCountAtStartOfLoad; + retryAction = + configureRetry(loadable, extractedSamplesCount) + ? (madeProgress ? Loader.RETRY_RESET_ERROR_COUNT : Loader.RETRY) + : Loader.DONT_RETRY; + } + boolean wasCanceled = + retryAction == Loader.DONT_RETRY || retryAction == Loader.DONT_RETRY_FATAL; eventDispatcher.loadError( loadable.dataSpec, + loadable.dataSource.getLastOpenedUri(), C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, /* trackFormat= */ null, @@ -545,18 +568,10 @@ import java.util.Arrays; durationUs, elapsedRealtimeMs, loadDurationMs, - loadable.bytesLoaded, + loadable.dataSource.getBytesRead(), error, - /* wasCanceled= */ isErrorFatal); - copyLengthFromLoader(loadable); - if (isErrorFatal) { - return Loader.DONT_RETRY_FATAL; - } - int extractedSamplesCount = getExtractedSamplesCount(); - boolean madeProgress = extractedSamplesCount > extractedSamplesCountAtStartOfLoad; - return configureRetry(loadable, extractedSamplesCount) - ? (madeProgress ? Loader.RETRY_RESET_ERROR_COUNT : Loader.RETRY) - : Loader.DONT_RETRY; + wasCanceled); + return retryAction; } // ExtractorOutput implementation. Called by the loading thread. @@ -657,6 +672,7 @@ import java.util.Arrays; long elapsedRealtimeMs = loader.startLoading(loadable, this, actualMinLoadableRetryCount); eventDispatcher.loadStarted( loadable.dataSpec, + loadable.dataSpec.uri, C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, /* trackFormat= */ null, @@ -797,7 +813,7 @@ import java.util.Arrays; /* package */ final class ExtractingLoadable implements Loadable { private final Uri uri; - private final DataSource dataSource; + private final StatsDataSource dataSource; private final ExtractorHolder extractorHolder; private final ConditionVariable loadCondition; private final PositionHolder positionHolder; @@ -808,17 +824,17 @@ import java.util.Arrays; private long seekTimeUs; private DataSpec dataSpec; private long length; - private long bytesLoaded; public ExtractingLoadable(Uri uri, DataSource dataSource, ExtractorHolder extractorHolder, ConditionVariable loadCondition) { this.uri = Assertions.checkNotNull(uri); - this.dataSource = Assertions.checkNotNull(dataSource); + this.dataSource = new StatsDataSource(dataSource); this.extractorHolder = Assertions.checkNotNull(extractorHolder); this.loadCondition = loadCondition; this.positionHolder = new PositionHolder(); this.pendingExtractorSeek = true; this.length = C.LENGTH_UNSET; + dataSpec = new DataSpec(uri, positionHolder.position, C.LENGTH_UNSET, customCacheKey); } public void setLoadPosition(long position, long timeUs) { @@ -832,11 +848,6 @@ import java.util.Arrays; loadCanceled = true; } - @Override - public boolean isLoadCanceled() { - return loadCanceled; - } - @Override public void load() throws IOException, InterruptedException { int result = Extractor.RESULT_CONTINUE; @@ -869,7 +880,6 @@ import java.util.Arrays; result = Extractor.RESULT_CONTINUE; } else if (input != null) { positionHolder.position = input.getPosition(); - bytesLoaded = positionHolder.position - dataSpec.absoluteStreamPosition; } Util.closeQuietly(dataSource); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ExtractorMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ExtractorMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 74627e61f..f079c3332 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ExtractorMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.net.Uri; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorsFactory; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorsFactory; -import org.telegram.messenger.exoplayer2.source.ads.AdsMediaSource; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; +import com.google.android.exoplayer2.source.ads.AdsMediaSource; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; /** @@ -67,40 +68,6 @@ public final class ExtractorMediaSource extends BaseMediaSource } - /** - * The default minimum number of times to retry loading prior to failing for on-demand streams. - */ - public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND = 3; - - /** - * The default minimum number of times to retry loading prior to failing for live streams. - */ - public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE = 6; - - /** - * Value for {@code minLoadableRetryCount} that causes the loader to retry - * {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE} times for live streams and - * {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND} for on-demand streams. - */ - public static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1; - - /** - * The default number of bytes that should be loaded between each each invocation of - * {@link MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}. - */ - public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024; - - private final Uri uri; - private final DataSource.Factory dataSourceFactory; - private final ExtractorsFactory extractorsFactory; - private final int minLoadableRetryCount; - private final String customCacheKey; - private final int continueLoadingCheckIntervalBytes; - private final @Nullable Object tag; - - private long timelineDurationUs; - private boolean timelineIsSeekable; - /** Factory for {@link ExtractorMediaSource}s. */ public static final class Factory implements AdsMediaSource.MediaSourceFactory { @@ -157,8 +124,8 @@ public final class ExtractorMediaSource extends BaseMediaSource /** * Sets a tag for the media source which will be published in the {@link - * org.telegram.messenger.exoplayer2.Timeline} of the source as {@link - * org.telegram.messenger.exoplayer2.Timeline.Window#tag}. + * com.google.android.exoplayer2.Timeline} of the source as {@link + * com.google.android.exoplayer2.Timeline.Window#tag}. * * @param tag A tag for the media source. * @return This factory, for convenience. @@ -243,6 +210,39 @@ public final class ExtractorMediaSource extends BaseMediaSource } } + /** + * The default minimum number of times to retry loading prior to failing for on-demand streams. + */ + public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND = 3; + + /** The default minimum number of times to retry loading prior to failing for live streams. */ + public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE = 6; + + /** + * Value for {@code minLoadableRetryCount} that causes the loader to retry {@link + * #DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE} times for live streams and {@link + * #DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND} for on-demand streams. + */ + public static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1; + + /** + * The default number of bytes that should be loaded between each each invocation of {@link + * MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}. + */ + public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024; + + private final Uri uri; + private final DataSource.Factory dataSourceFactory; + private final ExtractorsFactory extractorsFactory; + private final int minLoadableRetryCount; + private final String customCacheKey; + private final int continueLoadingCheckIntervalBytes; + private final @Nullable Object tag; + + private long timelineDurationUs; + private boolean timelineIsSeekable; + private @Nullable TransferListener transferListener; + /** * @param uri The {@link Uri} of the media stream. * @param dataSourceFactory A factory for {@link DataSource}s to read the media. @@ -344,7 +344,11 @@ public final class ExtractorMediaSource extends BaseMediaSource } @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + transferListener = mediaTransferListener; notifySourceInfoRefreshed(timelineDurationUs, /* isSeekable= */ false); } @@ -356,9 +360,13 @@ public final class ExtractorMediaSource extends BaseMediaSource @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { Assertions.checkArgument(id.periodIndex == 0); + DataSource dataSource = dataSourceFactory.createDataSource(); + if (transferListener != null) { + dataSource.addTransferListener(transferListener); + } return new ExtractorMediaPeriod( uri, - dataSourceFactory.createDataSource(), + dataSource, extractorsFactory.createExtractors(), minLoadableRetryCount, createEventDispatcher(id), diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ForwardingTimeline.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ForwardingTimeline.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ForwardingTimeline.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ForwardingTimeline.java index 883385425..45997aced 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ForwardingTimeline.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ForwardingTimeline.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Timeline; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Timeline; /** * An overridable {@link Timeline} implementation forwarding all methods to another timeline. @@ -77,4 +77,8 @@ public abstract class ForwardingTimeline extends Timeline { return timeline.getIndexOfPeriod(uid); } + @Override + public Object getUidOfPeriod(int periodIndex) { + return timeline.getUidOfPeriod(periodIndex); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/LoopingMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/LoopingMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index cb6608531..d370a3330 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/LoopingMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.ShuffleOrder.UnshuffledShuffleOrder; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ShuffleOrder.UnshuffledShuffleOrder; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; /** * Loops a {@link MediaSource} a specified number of times. @@ -60,8 +61,11 @@ public final class LoopingMediaSource extends CompositeMediaSource { } @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { - super.prepareSourceInternal(player, isTopLevelSource); + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener); prepareChildSource(/* id= */ null, childSource); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 4b6238a3a..997f94bbf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.trackselection.TrackSelection; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSource.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 4457dcf81..cba636b69 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; /** @@ -32,7 +33,7 @@ import java.io.IOException; * provide a new timeline whenever the structure of the media changes. The MediaSource * provides these timelines by calling {@link SourceInfoRefreshListener#onSourceInfoRefreshed} * on the {@link SourceInfoRefreshListener}s passed to {@link #prepareSource(ExoPlayer, - * boolean, SourceInfoRefreshListener)}. + * boolean, SourceInfoRefreshListener, TransferListener)}. *
  • To provide {@link MediaPeriod} instances for the periods in its timeline. MediaPeriods are * obtained by calling {@link #createPeriod(MediaPeriodId, Allocator)}, and provide a way for * the player to load and read the media. @@ -89,6 +90,15 @@ public interface MediaSource { */ public final long windowSequenceNumber; + /** + * The end position of the media to play within the media period, in microseconds, or {@link + * C#TIME_END_OF_SOURCE} if the end position is the end of the media period. + * + *

    Note that this only applies if the media period is for content (i.e., not for an ad) and + * is clipped to the position of the next ad group. + */ + public final long endPositionUs; + /** * Creates a media period identifier for a dummy period which is not part of a buffered sequence * of windows. @@ -107,7 +117,20 @@ public interface MediaSource { * windows this media period is part of. */ public MediaPeriodId(int periodIndex, long windowSequenceNumber) { - this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber); + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, C.TIME_END_OF_SOURCE); + } + + /** + * Creates a media period identifier for the specified clipped period in the timeline. + * + * @param periodIndex The timeline period index. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. + * @param endPositionUs The end position of the media period within the timeline period, in + * microseconds. + */ + public MediaPeriodId(int periodIndex, long windowSequenceNumber, long endPositionUs) { + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, endPositionUs); } /** @@ -122,10 +145,20 @@ public interface MediaSource { */ public MediaPeriodId( int periodIndex, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { + this(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, C.TIME_END_OF_SOURCE); + } + + private MediaPeriodId( + int periodIndex, + int adGroupIndex, + int adIndexInAdGroup, + long windowSequenceNumber, + long endPositionUs) { this.periodIndex = periodIndex; this.adGroupIndex = adGroupIndex; this.adIndexInAdGroup = adIndexInAdGroup; this.windowSequenceNumber = windowSequenceNumber; + this.endPositionUs = endPositionUs; } /** @@ -134,7 +167,8 @@ public interface MediaSource { public MediaPeriodId copyWithPeriodIndex(int newPeriodIndex) { return periodIndex == newPeriodIndex ? this - : new MediaPeriodId(newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); + : new MediaPeriodId( + newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, endPositionUs); } /** @@ -157,7 +191,8 @@ public interface MediaSource { return periodIndex == periodId.periodIndex && adGroupIndex == periodId.adGroupIndex && adIndexInAdGroup == periodId.adIndexInAdGroup - && windowSequenceNumber == periodId.windowSequenceNumber; + && windowSequenceNumber == periodId.windowSequenceNumber + && endPositionUs == periodId.endPositionUs; } @Override @@ -167,6 +202,7 @@ public interface MediaSource { result = 31 * result + adGroupIndex; result = 31 * result + adIndexInAdGroup; result = 31 * result + (int) windowSequenceNumber; + result = 31 * result + (int) endPositionUs; return result; } @@ -189,6 +225,11 @@ public interface MediaSource { */ void removeEventListener(MediaSourceEventListener eventListener); + /** @deprecated Will be removed in the next release. */ + @Deprecated + void prepareSource( + ExoPlayer player, boolean isTopLevelSource, SourceInfoRefreshListener listener); + /** * Starts source preparation if not yet started, and adds a listener for timeline and/or manifest * updates. @@ -206,9 +247,16 @@ public interface MediaSource { * boolean)}. If {@code false}, this source is being prepared by another source (e.g. {@link * ConcatenatingMediaSource}) for composition. * @param listener The listener to be added. + * @param mediaTransferListener The transfer listener which should be informed of any media data + * transfers. May be null if no listener is available. Note that this listener should be only + * informed of transfers related to the media loads and not of auxiliary loads for manifests + * and other data. */ void prepareSource( - ExoPlayer player, boolean isTopLevelSource, SourceInfoRefreshListener listener); + ExoPlayer player, + boolean isTopLevelSource, + SourceInfoRefreshListener listener, + @Nullable TransferListener mediaTransferListener); /** * Throws any pending error encountered while loading or refreshing source information. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSourceEventListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSourceEventListener.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSourceEventListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSourceEventListener.java index 56a431507..844534a43 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MediaSourceEventListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MediaSourceEventListener.java @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.support.annotation.CheckResult; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.concurrent.CopyOnWriteArrayList; @@ -35,8 +36,14 @@ public interface MediaSourceEventListener { /** Media source load event information. */ final class LoadEventInfo { - /** Defines the data being loaded. */ + /** Defines the requested data. */ public final DataSpec dataSpec; + /** + * The {@link Uri} from which data is being read. The uri will be identical to the one in {@link + * #dataSpec}.uri unless redirection has occurred. If redirection has occurred, this is the uri + * after redirection. + */ + public final Uri uri; /** The value of {@link SystemClock#elapsedRealtime} at the time of the load event. */ public final long elapsedRealtimeMs; /** The duration of the load up to the event time. */ @@ -47,15 +54,20 @@ public interface MediaSourceEventListener { /** * Creates load event info. * - * @param dataSpec Defines the data being loaded. + * @param dataSpec Defines the requested data. + * @param uri The {@link Uri} from which data is being read. The uri must be identical to the + * one in {@code dataSpec.uri} unless redirection has occurred. If redirection has occurred, + * this is the uri after redirection. * @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} at the time of the * load event. * @param loadDurationMs The duration of the load up to the event time. - * @param bytesLoaded The number of bytes that were loaded up to the event time. + * @param bytesLoaded The number of bytes that were loaded up to the event time. For compressed + * network responses, this is the decompressed size. */ public LoadEventInfo( - DataSpec dataSpec, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) { + DataSpec dataSpec, Uri uri, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) { this.dataSpec = dataSpec; + this.uri = uri; this.elapsedRealtimeMs = elapsedRealtimeMs; this.loadDurationMs = loadDurationMs; this.bytesLoaded = bytesLoaded; @@ -155,7 +167,8 @@ public interface MediaSourceEventListener { * @param windowIndex The window index in the timeline of the media source this load belongs to. * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not * belong to a specific media period. - * @param loadEventInfo The {@link LoadEventInfo} defining the load event. + * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The value of {@link + * LoadEventInfo#uri} won't reflect potential redirection yet. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ void onLoadStarted( @@ -170,7 +183,10 @@ public interface MediaSourceEventListener { * @param windowIndex The window index in the timeline of the media source this load belongs to. * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not * belong to a specific media period. - * @param loadEventInfo The {@link LoadEventInfo} defining the load event. + * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link + * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the + * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)} + * event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ void onLoadCompleted( @@ -185,7 +201,10 @@ public interface MediaSourceEventListener { * @param windowIndex The window index in the timeline of the media source this load belongs to. * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not * belong to a specific media period. - * @param loadEventInfo The {@link LoadEventInfo} defining the load event. + * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link + * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the + * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)} + * event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. */ void onLoadCanceled( @@ -211,7 +230,10 @@ public interface MediaSourceEventListener { * @param windowIndex The window index in the timeline of the media source this load belongs to. * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not * belong to a specific media period. - * @param loadEventInfo The {@link LoadEventInfo} defining the load event. + * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link + * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the + * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)} + * event. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. * @param error The load error. * @param wasCanceled Whether the load was canceled as a result of the error. @@ -268,7 +290,7 @@ public interface MediaSourceEventListener { /** Creates an event dispatcher. */ public EventDispatcher() { this( - /* listenerAndHandlers= */ new CopyOnWriteArrayList(), + /* listenerAndHandlers= */ new CopyOnWriteArrayList<>(), /* windowIndex= */ 0, /* mediaPeriodId= */ null, /* mediaTimeOffsetMs= */ 0); @@ -327,40 +349,31 @@ public interface MediaSourceEventListener { /** Dispatches {@link #onMediaPeriodCreated(int, MediaPeriodId)}. */ public void mediaPeriodCreated() { - Assertions.checkState(mediaPeriodId != null); + MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId); for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onMediaPeriodCreated(windowIndex, mediaPeriodId); - } - }); + () -> listener.onMediaPeriodCreated(windowIndex, mediaPeriodId)); } } /** Dispatches {@link #onMediaPeriodReleased(int, MediaPeriodId)}. */ public void mediaPeriodReleased() { - Assertions.checkState(mediaPeriodId != null); + MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId); for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onMediaPeriodReleased(windowIndex, mediaPeriodId); - } - }); + () -> listener.onMediaPeriodReleased(windowIndex, mediaPeriodId)); } } /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ - public void loadStarted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs) { + public void loadStarted(DataSpec dataSpec, Uri uri, int dataType, long elapsedRealtimeMs) { loadStarted( dataSpec, + uri, dataType, C.TRACK_TYPE_UNKNOWN, null, @@ -374,6 +387,7 @@ public interface MediaSourceEventListener { /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ public void loadStarted( DataSpec dataSpec, + Uri uri, int dataType, int trackType, @Nullable Format trackFormat, @@ -384,7 +398,7 @@ public interface MediaSourceEventListener { long elapsedRealtimeMs) { loadStarted( new LoadEventInfo( - dataSpec, elapsedRealtimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0), + dataSpec, uri, elapsedRealtimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0), new MediaLoadData( dataType, trackType, @@ -396,29 +410,26 @@ public interface MediaSourceEventListener { } /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ - public void loadStarted(final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) { + public void loadStarted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData); - } - }); + () -> listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData)); } } /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ public void loadCompleted( DataSpec dataSpec, + Uri uri, int dataType, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) { loadCompleted( dataSpec, + uri, dataType, C.TRACK_TYPE_UNKNOWN, null, @@ -434,6 +445,7 @@ public interface MediaSourceEventListener { /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ public void loadCompleted( DataSpec dataSpec, + Uri uri, int dataType, int trackType, @Nullable Format trackFormat, @@ -445,7 +457,7 @@ public interface MediaSourceEventListener { long loadDurationMs, long bytesLoaded) { loadCompleted( - new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded), + new LoadEventInfo(dataSpec, uri, elapsedRealtimeMs, loadDurationMs, bytesLoaded), new MediaLoadData( dataType, trackType, @@ -457,30 +469,27 @@ public interface MediaSourceEventListener { } /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ - public void loadCompleted( - final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) { + public void loadCompleted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData); - } - }); + () -> + listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData)); } } /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ public void loadCanceled( DataSpec dataSpec, + Uri uri, int dataType, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) { loadCanceled( dataSpec, + uri, dataType, C.TRACK_TYPE_UNKNOWN, null, @@ -496,6 +505,7 @@ public interface MediaSourceEventListener { /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ public void loadCanceled( DataSpec dataSpec, + Uri uri, int dataType, int trackType, @Nullable Format trackFormat, @@ -507,7 +517,7 @@ public interface MediaSourceEventListener { long loadDurationMs, long bytesLoaded) { loadCanceled( - new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded), + new LoadEventInfo(dataSpec, uri, elapsedRealtimeMs, loadDurationMs, bytesLoaded), new MediaLoadData( dataType, trackType, @@ -519,17 +529,13 @@ public interface MediaSourceEventListener { } /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */ - public void loadCanceled(final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) { + public void loadCanceled(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { - final MediaSourceEventListener listener = listenerAndHandler.listener; + MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData); - } - }); + () -> + listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData)); } } @@ -539,6 +545,7 @@ public interface MediaSourceEventListener { */ public void loadError( DataSpec dataSpec, + Uri uri, int dataType, long elapsedRealtimeMs, long loadDurationMs, @@ -547,6 +554,7 @@ public interface MediaSourceEventListener { boolean wasCanceled) { loadError( dataSpec, + uri, dataType, C.TRACK_TYPE_UNKNOWN, null, @@ -567,6 +575,7 @@ public interface MediaSourceEventListener { */ public void loadError( DataSpec dataSpec, + Uri uri, int dataType, int trackType, @Nullable Format trackFormat, @@ -580,7 +589,7 @@ public interface MediaSourceEventListener { IOException error, boolean wasCanceled) { loadError( - new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded), + new LoadEventInfo(dataSpec, uri, elapsedRealtimeMs, loadDurationMs, bytesLoaded), new MediaLoadData( dataType, trackType, @@ -598,37 +607,28 @@ public interface MediaSourceEventListener { * boolean)}. */ public void loadError( - final LoadEventInfo loadEventInfo, - final MediaLoadData mediaLoadData, - final IOException error, - final boolean wasCanceled) { + LoadEventInfo loadEventInfo, + MediaLoadData mediaLoadData, + IOException error, + boolean wasCanceled) { for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { + () -> listener.onLoadError( - windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled); - } - }); + windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled)); } } /** Dispatches {@link #onReadingStarted(int, MediaPeriodId)}. */ public void readingStarted() { - Assertions.checkState(mediaPeriodId != null); + MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId); for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onReadingStarted(windowIndex, mediaPeriodId); - } - }); + () -> listener.onReadingStarted(windowIndex, mediaPeriodId)); } } @@ -646,17 +646,13 @@ public interface MediaSourceEventListener { } /** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */ - public void upstreamDiscarded(final MediaLoadData mediaLoadData) { + public void upstreamDiscarded(MediaLoadData mediaLoadData) { + MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId); for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onUpstreamDiscarded(windowIndex, mediaPeriodId, mediaLoadData); - } - }); + () -> listener.onUpstreamDiscarded(windowIndex, mediaPeriodId, mediaLoadData)); } } @@ -679,17 +675,12 @@ public interface MediaSourceEventListener { } /** Dispatches {@link #onDownstreamFormatChanged(int, MediaPeriodId, MediaLoadData)}. */ - public void downstreamFormatChanged(final MediaLoadData mediaLoadData) { + public void downstreamFormatChanged(MediaLoadData mediaLoadData) { for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) { final MediaSourceEventListener listener = listenerAndHandler.listener; postOrRun( listenerAndHandler.handler, - new Runnable() { - @Override - public void run() { - listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData); - } - }); + () -> listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index 4fd3d302f..a4fc8c6b0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java index 03339d22b..b29eb60af 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/MergingMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -97,8 +98,11 @@ public final class MergingMediaSource extends CompositeMediaSource { } @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { - super.prepareSourceInternal(player, isTopLevelSource); + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener); for (int i = 0; i < mediaSources.length; i++) { prepareChildSource(i, mediaSources[i]); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleMetadataQueue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleMetadataQueue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index aaef972ed..e5b950cf2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleMetadataQueue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput.CryptoData; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.extractor.TrackOutput.CryptoData; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; /** * A queue of metadata describing the contents of a media buffer. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleQueue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleQueue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index bf4c2e8c4..c378a8f9a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleQueue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.source.SampleMetadataQueue.SampleExtrasHolder; -import org.telegram.messenger.exoplayer2.upstream.Allocation; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.SampleMetadataQueue.SampleExtrasHolder; +import com.google.android.exoplayer2.upstream.Allocation; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; @@ -568,8 +568,12 @@ public final class SampleQueue implements TrackOutput { } @Override - public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData cryptoData) { + public void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData cryptoData) { if (pendingFormatAdjustment) { format(lastUnadjustedFormat); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleStream.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleStream.java index 8e9618d20..06efc980e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SampleStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SampleStream.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SequenceableLoader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SequenceableLoader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java index fea23c7f6..182f0f17c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SequenceableLoader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; // TODO: Clarify the requirements for implementing this interface [Internal ref: b/36250203]. /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ShuffleOrder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ShuffleOrder.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ShuffleOrder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ShuffleOrder.java index 40ad9d6a9..f5f98e4d8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ShuffleOrder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ShuffleOrder.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.util.Arrays; import java.util.Random; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SinglePeriodTimeline.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SinglePeriodTimeline.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java index 634df638d..9e33a2d89 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SinglePeriodTimeline.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.util.Assertions; /** * A {@link Timeline} consisting of a single period and static window. @@ -193,4 +193,9 @@ public final class SinglePeriodTimeline extends Timeline { return UID.equals(uid) ? 0 : C.INDEX_UNSET; } + @Override + public Object getUidOfPeriod(int periodIndex) { + Assertions.checkIndex(periodIndex, 0, 1); + return UID; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index 084a51b4f..e0dab510a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -13,21 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.upstream.Loader.Loadable; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.upstream.Loader.Loadable; +import com.google.android.exoplayer2.upstream.StatsDataSource; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -45,6 +49,7 @@ import java.util.Arrays; private final DataSpec dataSpec; private final DataSource.Factory dataSourceFactory; + private final @Nullable TransferListener transferListener; private final int minLoadableRetryCount; private final EventDispatcher eventDispatcher; private final TrackGroupArray tracks; @@ -61,11 +66,11 @@ import java.util.Arrays; /* package */ boolean loadingSucceeded; /* package */ byte[] sampleData; /* package */ int sampleSize; - private int errorCount; public SingleSampleMediaPeriod( DataSpec dataSpec, DataSource.Factory dataSourceFactory, + @Nullable TransferListener transferListener, Format format, long durationUs, int minLoadableRetryCount, @@ -73,6 +78,7 @@ import java.util.Arrays; boolean treatLoadErrorsAsEndOfStream) { this.dataSpec = dataSpec; this.dataSourceFactory = dataSourceFactory; + this.transferListener = transferListener; this.format = format; this.durationUs = durationUs; this.minLoadableRetryCount = minLoadableRetryCount; @@ -137,13 +143,16 @@ import java.util.Arrays; if (loadingFinished || loader.isLoading()) { return false; } + DataSource dataSource = dataSourceFactory.createDataSource(); + if (transferListener != null) { + dataSource.addTransferListener(transferListener); + } long elapsedRealtimeMs = loader.startLoading( - new SourceLoadable(dataSpec, dataSourceFactory.createDataSource()), - this, - minLoadableRetryCount); + new SourceLoadable(dataSpec, dataSource), /* callback= */ this, minLoadableRetryCount); eventDispatcher.loadStarted( dataSpec, + dataSpec.uri, C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, format, @@ -192,8 +201,13 @@ import java.util.Arrays; @Override public void onLoadCompleted(SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { + sampleSize = (int) loadable.dataSource.getBytesRead(); + sampleData = loadable.sampleData; + loadingFinished = true; + loadingSucceeded = true; eventDispatcher.loadCompleted( loadable.dataSpec, + loadable.dataSource.getLastOpenedUri(), C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, format, @@ -203,11 +217,7 @@ import java.util.Arrays; durationUs, elapsedRealtimeMs, loadDurationMs, - loadable.sampleSize); - sampleSize = loadable.sampleSize; - sampleData = loadable.sampleData; - loadingFinished = true; - loadingSucceeded = true; + sampleSize); } @Override @@ -215,6 +225,7 @@ import java.util.Arrays; boolean released) { eventDispatcher.loadCanceled( loadable.dataSpec, + loadable.dataSource.getLastOpenedUri(), C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, /* trackFormat= */ null, @@ -224,16 +235,20 @@ import java.util.Arrays; durationUs, elapsedRealtimeMs, loadDurationMs, - loadable.sampleSize); + loadable.dataSource.getBytesRead()); } @Override - public @Loader.RetryAction int onLoadError( - SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { - errorCount++; + public LoadErrorAction onLoadError( + SourceLoadable loadable, + long elapsedRealtimeMs, + long loadDurationMs, + IOException error, + int errorCount) { boolean cancel = treatLoadErrorsAsEndOfStream && errorCount >= minLoadableRetryCount; eventDispatcher.loadError( loadable.dataSpec, + loadable.dataSource.getLastOpenedUri(), C.DATA_TYPE_MEDIA, C.TRACK_TYPE_UNKNOWN, format, @@ -243,7 +258,7 @@ import java.util.Arrays; durationUs, elapsedRealtimeMs, loadDurationMs, - loadable.sampleSize, + loadable.dataSource.getBytesRead(), error, /* wasCanceled= */ cancel); if (cancel) { @@ -333,14 +348,13 @@ import java.util.Arrays; public final DataSpec dataSpec; - private final DataSource dataSource; + private final StatsDataSource dataSource; - private int sampleSize; private byte[] sampleData; public SourceLoadable(DataSpec dataSpec, DataSource dataSource) { this.dataSpec = dataSpec; - this.dataSource = dataSource; + this.dataSource = new StatsDataSource(dataSource); } @Override @@ -348,22 +362,17 @@ import java.util.Arrays; // Never happens. } - @Override - public boolean isLoadCanceled() { - return false; - } - @Override public void load() throws IOException, InterruptedException { - // We always load from the beginning, so reset the sampleSize to 0. - sampleSize = 0; + // We always load from the beginning, so reset bytesRead to 0. + dataSource.resetBytesRead(); try { // Create and open the input. dataSource.open(dataSpec); // Load the sample data. int result = 0; while (result != C.RESULT_END_OF_INPUT) { - sampleSize += result; + int sampleSize = (int) dataSource.getBytesRead(); if (sampleData == null) { sampleData = new byte[INITIAL_SAMPLE_SIZE]; } else if (sampleSize == sampleData.length) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index b4b0c9e5a..2c8213fc4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/SingleSampleMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -13,18 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.net.Uri; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; /** @@ -168,6 +169,8 @@ public final class SingleSampleMediaSource extends BaseMediaSource { private final boolean treatLoadErrorsAsEndOfStream; private final Timeline timeline; + private @Nullable TransferListener transferListener; + /** * @param uri The {@link Uri} of the media stream. * @param dataSourceFactory The factory from which the {@link DataSource} to read the media will @@ -268,7 +271,11 @@ public final class SingleSampleMediaSource extends BaseMediaSource { // MediaSource implementation. @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + transferListener = mediaTransferListener; refreshSourceInfo(timeline, /* manifest= */ null); } @@ -283,6 +290,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { return new SingleSampleMediaPeriod( dataSpec, dataSourceFactory, + transferListener, format, durationUs, minLoadableRetryCount, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroup.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroup.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java index c22f619a6..56c9989f3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroup.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Assertions; import java.util.Arrays; // TODO: Add an allowMultipleStreams boolean to indicate where the one stream per group restriction @@ -72,11 +72,14 @@ public final class TrackGroup implements Parcelable { } /** - * Returns the index of the track with the given format in the group. + * Returns the index of the track with the given format in the group. The format is located by + * identity so, for example, {@code group.indexOf(group.getFormat(index)) == index} even if + * multiple tracks have formats that contain the same values. * * @param format The format. * @return The index of the track, or {@link C#INDEX_UNSET} if no such track exists. */ + @SuppressWarnings("ReferenceEquality") public int indexOf(Format format) { for (int i = 0; i < formats.length; i++) { if (format == formats[i]) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroupArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroupArray.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroupArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroupArray.java index 41f7ea940..a155032a9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/TrackGroupArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/TrackGroupArray.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.util.Arrays; /** An array of {@link TrackGroup}s exposed by a {@link MediaPeriod}. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/UnrecognizedInputFormatException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/UnrecognizedInputFormatException.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/UnrecognizedInputFormatException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/UnrecognizedInputFormatException.java index 86cd4349a..508bf0e36 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/UnrecognizedInputFormatException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/UnrecognizedInputFormatException.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source; +package com.google.android.exoplayer2.source; import android.net.Uri; -import org.telegram.messenger.exoplayer2.ParserException; +import com.google.android.exoplayer2.ParserException; /** * Thrown if the input format was not recognized. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdPlaybackState.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdPlaybackState.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java index cf8f31077..53f0a418b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdPlaybackState.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.ads; +package com.google.android.exoplayer2.source.ads; import android.net.Uri; import android.support.annotation.CheckResult; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -96,6 +96,30 @@ public final class AdPlaybackState { return count == C.LENGTH_UNSET || getFirstAdIndexToPlay() < count; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AdGroup adGroup = (AdGroup) o; + return count == adGroup.count + && Arrays.equals(uris, adGroup.uris) + && Arrays.equals(states, adGroup.states) + && Arrays.equals(durationsUs, adGroup.durationsUs); + } + + @Override + public int hashCode() { + int result = count; + result = 31 * result + Arrays.hashCode(uris); + result = 31 * result + Arrays.hashCode(states); + result = 31 * result + Arrays.hashCode(durationsUs); + return result; + } + /** * Returns a new instance with the ad count set to {@code count}. This method may only be called * if this instance's ad count has not yet been specified. @@ -344,6 +368,14 @@ public final class AdPlaybackState { return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs); } + /** Returns an instance with the specified ad marked as skipped. */ + @CheckResult + public AdPlaybackState withSkippedAd(int adGroupIndex, int adIndexInAdGroup) { + AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length); + adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdState(AD_STATE_SKIPPED, adIndexInAdGroup); + return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs); + } + /** Returns an instance with the specified ad marked as having a load error. */ @CheckResult public AdPlaybackState withAdLoadError(int adGroupIndex, int adIndexInAdGroup) { @@ -393,4 +425,29 @@ public final class AdPlaybackState { } } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AdPlaybackState that = (AdPlaybackState) o; + return adGroupCount == that.adGroupCount + && adResumePositionUs == that.adResumePositionUs + && contentDurationUs == that.contentDurationUs + && Arrays.equals(adGroupTimesUs, that.adGroupTimesUs) + && Arrays.equals(adGroups, that.adGroups); + } + + @Override + public int hashCode() { + int result = adGroupCount; + result = 31 * result + (int) adResumePositionUs; + result = 31 * result + (int) contentDurationUs; + result = 31 * result + Arrays.hashCode(adGroupTimesUs); + result = 31 * result + Arrays.hashCode(adGroups); + return result; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsLoader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsLoader.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsLoader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsLoader.java index 5e147c0e3..d05c51a79 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsLoader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsLoader.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.ads; +package com.google.android.exoplayer2.source.ads; import android.view.ViewGroup; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.source.ads.AdsMediaSource.AdLoadException; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException; +import com.google.android.exoplayer2.upstream.DataSpec; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java index e2e95f33b..fed3d1526 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/AdsMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.ads; +package com.google.android.exoplayer2.source.ads; import android.net.Uri; import android.os.Handler; @@ -21,22 +21,23 @@ import android.os.Looper; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.view.ViewGroup; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.CompositeMediaSource; -import org.telegram.messenger.exoplayer2.source.DeferredMediaPeriod; -import org.telegram.messenger.exoplayer2.source.ExtractorMediaSource; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.CompositeMediaSource; +import com.google.android.exoplayer2.source.DeferredMediaPeriod; +import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; +import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -169,7 +170,9 @@ public final class AdsMediaSource extends CompositeMediaSource { } - private static final String TAG = "AdsMediaSource"; + // Used to identify the content "child" source for CompositeMediaSource. + private static final MediaPeriodId DUMMY_CONTENT_MEDIA_PERIOD_ID = + new MediaPeriodId(/* periodIndex= */ 0); private final MediaSource contentMediaSource; private final MediaSourceFactory adMediaSourceFactory; @@ -307,12 +310,15 @@ public final class AdsMediaSource extends CompositeMediaSource { } @Override - public void prepareSourceInternal(final ExoPlayer player, boolean isTopLevelSource) { - super.prepareSourceInternal(player, isTopLevelSource); + public void prepareSourceInternal( + final ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener); Assertions.checkArgument(isTopLevelSource); final ComponentListener componentListener = new ComponentListener(); this.componentListener = componentListener; - prepareChildSource(new MediaPeriodId(/* periodIndex= */ 0), contentMediaSource); + prepareChildSource(DUMMY_CONTENT_MEDIA_PERIOD_ID, contentMediaSource); mainHandler.post(new Runnable() { @Override public void run() { @@ -338,20 +344,18 @@ public final class AdsMediaSource extends CompositeMediaSource { Arrays.fill(adDurationsUs[adGroupIndex], oldAdCount, adCount, C.TIME_UNSET); } adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource; - deferredMediaPeriodByAdMediaSource.put(adMediaSource, new ArrayList()); + deferredMediaPeriodByAdMediaSource.put(adMediaSource, new ArrayList<>()); prepareChildSource(id, adMediaSource); } MediaSource mediaSource = adGroupMediaSources[adGroupIndex][adIndexInAdGroup]; - DeferredMediaPeriod deferredMediaPeriod = - new DeferredMediaPeriod( - mediaSource, - new MediaPeriodId(/* periodIndex= */ 0, id.windowSequenceNumber), - allocator); + DeferredMediaPeriod deferredMediaPeriod = new DeferredMediaPeriod(mediaSource, id, allocator); deferredMediaPeriod.setPrepareErrorListener( new AdPrepareErrorListener(adUri, adGroupIndex, adIndexInAdGroup)); List mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource); if (mediaPeriods == null) { - deferredMediaPeriod.createPeriod(); + MediaPeriodId adSourceMediaPeriodId = + new MediaPeriodId(/* periodIndex= */ 0, id.windowSequenceNumber); + deferredMediaPeriod.createPeriod(adSourceMediaPeriodId); } else { // Keep track of the deferred media period so it can be populated with the real media period // when the source's info becomes available. @@ -360,7 +364,7 @@ public final class AdsMediaSource extends CompositeMediaSource { return deferredMediaPeriod; } else { DeferredMediaPeriod mediaPeriod = new DeferredMediaPeriod(contentMediaSource, id, allocator); - mediaPeriod.createPeriod(); + mediaPeriod.createPeriod(id); return mediaPeriod; } } @@ -413,8 +417,8 @@ public final class AdsMediaSource extends CompositeMediaSource { @Override protected @Nullable MediaPeriodId getMediaPeriodIdForChildMediaPeriodId( MediaPeriodId childId, MediaPeriodId mediaPeriodId) { - // The child id for the content period is just a dummy without window sequence number. That's - // why we need to forward the reported mediaPeriodId in this case. + // The child id for the content period is just DUMMY_CONTENT_MEDIA_PERIOD_ID. That's why we need + // to forward the reported mediaPeriodId in this case. return childId.isAd() ? childId : mediaPeriodId; } @@ -441,12 +445,14 @@ public final class AdsMediaSource extends CompositeMediaSource { int adIndexInAdGroup, Timeline timeline) { Assertions.checkArgument(timeline.getPeriodCount() == 1); adDurationsUs[adGroupIndex][adIndexInAdGroup] = timeline.getPeriod(0, period).getDurationUs(); - if (deferredMediaPeriodByAdMediaSource.containsKey(mediaSource)) { - List mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource); + List mediaPeriods = deferredMediaPeriodByAdMediaSource.remove(mediaSource); + if (mediaPeriods != null) { for (int i = 0; i < mediaPeriods.size(); i++) { - mediaPeriods.get(i).createPeriod(); + DeferredMediaPeriod mediaPeriod = mediaPeriods.get(i); + MediaPeriodId adSourceMediaPeriodId = + new MediaPeriodId(/* periodIndex= */ 0, mediaPeriod.id.windowSequenceNumber); + mediaPeriod.createPeriod(adSourceMediaPeriodId); } - deferredMediaPeriodByAdMediaSource.remove(mediaSource); } maybeUpdateSourceInfo(); } @@ -541,6 +547,7 @@ public final class AdsMediaSource extends CompositeMediaSource { createEventDispatcher(/* mediaPeriodId= */ null) .loadError( dataSpec, + dataSpec.uri, C.DATA_TYPE_AD, C.TRACK_TYPE_UNKNOWN, /* loadDurationMs= */ 0, @@ -582,6 +589,7 @@ public final class AdsMediaSource extends CompositeMediaSource { createEventDispatcher(mediaPeriodId) .loadError( new DataSpec(adUri), + adUri, C.DATA_TYPE_AD, C.TRACK_TYPE_UNKNOWN, /* loadDurationMs= */ 0, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/SinglePeriodAdTimeline.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/SinglePeriodAdTimeline.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.java index 8bcbb443c..0594a635a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/ads/SinglePeriodAdTimeline.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.ads; +package com.google.android.exoplayer2.source.ads; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.ForwardingTimeline; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.VisibleForTesting; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ForwardingTimeline; +import com.google.android.exoplayer2.util.Assertions; -/** - * A {@link Timeline} for sources that have ads. - */ -/* package */ final class SinglePeriodAdTimeline extends ForwardingTimeline { +/** A {@link Timeline} for sources that have ads. */ +@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) +public final class SinglePeriodAdTimeline extends ForwardingTimeline { private final AdPlaybackState adPlaybackState; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunk.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunk.java index 3ef1788ff..e872f730d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunk.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; /** * A base implementation of {@link MediaChunk} that outputs to a {@link BaseMediaChunkOutput}. @@ -44,7 +44,7 @@ public abstract class BaseMediaChunk extends MediaChunk { * @param endTimeUs The end time of the media contained by the chunk, in microseconds. * @param seekTimeUs The media time from which output will begin, or {@link C#TIME_UNSET} if the * whole chunk should be output. - * @param chunkIndex The index of the chunk. + * @param chunkIndex The index of the chunk, or {@link C#INDEX_UNSET} if it is not known. */ public BaseMediaChunk( DataSource dataSource, diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkIterator.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkIterator.java new file mode 100755 index 000000000..68dd32244 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkIterator.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.chunk; + +import java.util.NoSuchElementException; + +/** + * Base class for {@link MediaChunkIterator}s. Handles {@link #next()} and {@link #isEnded()}, and + * provides a bounds check for child classes. + */ +public abstract class BaseMediaChunkIterator implements MediaChunkIterator { + + private final long fromIndex; + private final long toIndex; + + private long currentIndex; + + /** + * Creates base iterator. + * + * @param fromIndex The index at which the iterator will start. + * @param toIndex The last available index. + */ + public BaseMediaChunkIterator(long fromIndex, long toIndex) { + this.fromIndex = fromIndex; + this.toIndex = toIndex; + currentIndex = fromIndex - 1; + } + + @Override + public boolean isEnded() { + return currentIndex > toIndex; + } + + @Override + public boolean next() { + currentIndex++; + return !isEnded(); + } + + /** + * Verifies that the iterator points to a valid element. + * + * @throws NoSuchElementException If the iterator does not point to a valid element. + */ + protected void checkInBounds() { + if (currentIndex < fromIndex || currentIndex > toIndex) { + throw new NoSuchElementException(); + } + } + + /** Returns the current index this iterator is pointing to. */ + protected long getCurrentIndex() { + return currentIndex; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunkOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunkOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java index 9cb74dd0c..e0129e5c6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/BaseMediaChunkOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; import android.util.Log; -import org.telegram.messenger.exoplayer2.extractor.DummyTrackOutput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.source.SampleQueue; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; +import com.google.android.exoplayer2.extractor.DummyTrackOutput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; -/** - * An output for {@link BaseMediaChunk}s. - */ -/* package */ final class BaseMediaChunkOutput implements TrackOutputProvider { +/** An output for {@link BaseMediaChunk}s. */ +public final class BaseMediaChunkOutput implements TrackOutputProvider { private static final String TAG = "BaseMediaChunkOutput"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/Chunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java similarity index 68% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/Chunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java index c2e1bd475..5c109aef8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/Chunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java @@ -13,15 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; +import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.Loader.Loadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.Loader.Loadable; +import com.google.android.exoplayer2.upstream.StatsDataSource; +import com.google.android.exoplayer2.util.Assertions; +import java.util.List; +import java.util.Map; /** * An abstract base class for {@link Loadable} implementations that load chunks of data required @@ -64,7 +68,7 @@ public abstract class Chunk implements Loadable { */ public final long endTimeUs; - protected final DataSource dataSource; + protected final StatsDataSource dataSource; /** * @param dataSource The source from which the data should be loaded. @@ -85,7 +89,7 @@ public abstract class Chunk implements Loadable { @Nullable Object trackSelectionData, long startTimeUs, long endTimeUs) { - this.dataSource = Assertions.checkNotNull(dataSource); + this.dataSource = new StatsDataSource(dataSource); this.dataSpec = Assertions.checkNotNull(dataSpec); this.type = type; this.trackFormat = trackFormat; @@ -103,8 +107,31 @@ public abstract class Chunk implements Loadable { } /** - * Returns the number of bytes that have been loaded. + * Returns the number of bytes that have been loaded. Must only be called after the load + * completed, failed, or was canceled. */ - public abstract long bytesLoaded(); + public final long bytesLoaded() { + return dataSource.getBytesRead(); + } + /** + * Returns the {@link Uri} associated with the last {@link DataSource#open} call. If redirection + * occurred, this is the redirected uri. Must only be called after the load completed, failed, or + * was canceled. + * + * @see DataSource#getUri(). + */ + public final Uri getUri() { + return dataSource.getLastOpenedUri(); + } + + /** + * Returns the response headers associated with the last {@link DataSource#open} call. Must only + * be called after the load completed, failed, or was canceled. + * + * @see DataSource#getResponseHeaders(). + */ + public final Map> getResponseHeaders() { + return dataSource.getLastResponseHeaders(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkExtractorWrapper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java index 1fb3406e8..a3abc7560 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; +import android.support.annotation.Nullable; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.DummyTrackOutput; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.DummyTrackOutput; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; /** @@ -48,7 +49,7 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { * * @param id A track identifier. * @param type The type of the track. Typically one of the - * {@link org.telegram.messenger.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @return The {@link TrackOutput} for the given track identifier. */ TrackOutput track(int id, int type); @@ -69,7 +70,7 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { /** * @param extractor The extractor to wrap. * @param primaryTrackType The type of the primary track. Typically one of the - * {@link org.telegram.messenger.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param primaryTrackManifestFormat A manifest defined {@link Format} whose data should be merged * into any sample {@link Format} output from the {@link Extractor} for the primary track. */ @@ -103,7 +104,7 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { * @param seekTimeUs The seek position within the new chunk, or {@link C#TIME_UNSET} to output the * whole chunk. */ - public void init(TrackOutputProvider trackOutputProvider, long seekTimeUs) { + public void init(@Nullable TrackOutputProvider trackOutputProvider, long seekTimeUs) { this.trackOutputProvider = trackOutputProvider; if (!extractorInitialized) { extractor.init(this); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkHolder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkHolder.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkHolder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkHolder.java index 4faf07005..6b7f5688a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkHolder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkHolder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; /** * Holds a chunk or an indication that the end of the stream has been reached. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSampleStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSampleStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 5777d530d..b71b236c4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -13,23 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SampleQueue; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -385,9 +386,18 @@ public class ChunkSampleStream implements SampleStream, S @Override public void onLoadCompleted(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs) { chunkSource.onChunkLoadCompleted(loadable); - eventDispatcher.loadCompleted(loadable.dataSpec, loadable.type, primaryTrackType, - loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, - loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, + eventDispatcher.loadCompleted( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + primaryTrackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, loadable.bytesLoaded()); callback.onContinueLoadingRequested(this); } @@ -395,9 +405,18 @@ public class ChunkSampleStream implements SampleStream, S @Override public void onLoadCanceled(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released) { - eventDispatcher.loadCanceled(loadable.dataSpec, loadable.type, primaryTrackType, - loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, - loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, + eventDispatcher.loadCanceled( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + primaryTrackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, loadable.bytesLoaded()); if (!released) { primarySampleQueue.reset(); @@ -409,8 +428,12 @@ public class ChunkSampleStream implements SampleStream, S } @Override - public @Loader.RetryAction int onLoadError( - Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { + public LoadErrorAction onLoadError( + Chunk loadable, + long elapsedRealtimeMs, + long loadDurationMs, + IOException error, + int errorCount) { long bytesLoaded = loadable.bytesLoaded(); boolean isMediaChunk = isMediaChunk(loadable); int lastChunkIndex = mediaChunks.size() - 1; @@ -431,10 +454,21 @@ public class ChunkSampleStream implements SampleStream, S } } } - eventDispatcher.loadError(loadable.dataSpec, loadable.type, primaryTrackType, - loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, - loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, bytesLoaded, - error, canceled); + eventDispatcher.loadError( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + primaryTrackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, + bytesLoaded, + error, + canceled); if (canceled) { callback.onContinueLoadingRequested(this); return Loader.DONT_RETRY; @@ -452,16 +486,16 @@ public class ChunkSampleStream implements SampleStream, S } boolean pendingReset = isPendingReset(); - MediaChunk previousChunk; + List chunkQueue; long loadPositionUs; if (pendingReset) { - previousChunk = null; + chunkQueue = Collections.emptyList(); loadPositionUs = pendingResetPositionUs; } else { - previousChunk = getLastMediaChunk(); - loadPositionUs = previousChunk.endTimeUs; + chunkQueue = readOnlyMediaChunks; + loadPositionUs = getLastMediaChunk().endTimeUs; } - chunkSource.getNextChunk(previousChunk, positionUs, loadPositionUs, nextChunkHolder); + chunkSource.getNextChunk(positionUs, loadPositionUs, chunkQueue, nextChunkHolder); boolean endOfStream = nextChunkHolder.endOfStream; Chunk loadable = nextChunkHolder.chunk; nextChunkHolder.clear(); @@ -488,9 +522,17 @@ public class ChunkSampleStream implements SampleStream, S mediaChunks.add(mediaChunk); } long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount); - eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, primaryTrackType, - loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, - loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs); + eventDispatcher.loadStarted( + loadable.dataSpec, + loadable.dataSpec.uri, + loadable.type, + primaryTrackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs); return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java index 9bac4bbe2..be45138bd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.SeekParameters; import java.io.IOException; import java.util.List; @@ -59,22 +59,25 @@ public interface ChunkSource { /** * Returns the next chunk to load. - *

    - * If a chunk is available then {@link ChunkHolder#chunk} is set. If the end of the stream has + * + *

    If a chunk is available then {@link ChunkHolder#chunk} is set. If the end of the stream has * been reached then {@link ChunkHolder#endOfStream} is set. If a chunk is not available but the * end of the stream has not been reached, the {@link ChunkHolder} is not modified. * - * @param previous The most recently loaded media chunk. * @param playbackPositionUs The current playback position in microseconds. If playback of the * period to which this chunk source belongs has not yet started, the value will be the * starting position in the period minus the duration of any media in previous periods still * to be played. - * @param loadPositionUs The current load position in microseconds. If {@code previous} is null, + * @param loadPositionUs The current load position in microseconds. If {@code queue} is empty, * this is the starting position from which chunks should be provided. Else it's equal to - * {@code previous.endTimeUs}. + * {@link MediaChunk#endTimeUs} of the last chunk in the {@code queue}. + * @param queue The queue of buffered {@link MediaChunk}s. * @param out A holder to populate. */ - void getNextChunk(MediaChunk previous, long playbackPositionUs, long loadPositionUs, + void getNextChunk( + long playbackPositionUs, + long loadPositionUs, + List queue, ChunkHolder out); /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java index cefd2eb86..38e0c0d51 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkedTrackBlacklistUtil.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; import android.util.Log; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; /** * Helper class for blacklisting tracks in a {@link TrackSelection} when 404 (Not Found) and 410 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ContainerMediaChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java similarity index 78% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ContainerMediaChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java index 65d6cb6c6..2d5ba3d2e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/ContainerMediaChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java @@ -13,17 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.DefaultExtractorInput; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** @@ -31,13 +32,15 @@ import java.io.IOException; */ public class ContainerMediaChunk extends BaseMediaChunk { + private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); + private final int chunkCount; private final long sampleOffsetUs; private final ChunkExtractorWrapper extractorWrapper; - private volatile int bytesLoaded; + private long nextLoadPosition; private volatile boolean loadCanceled; - private volatile boolean loadCompleted; + private boolean loadCompleted; /** * @param dataSource The source from which the data should be loaded. @@ -49,7 +52,7 @@ public class ContainerMediaChunk extends BaseMediaChunk { * @param endTimeUs The end time of the media contained by the chunk, in microseconds. * @param seekTimeUs The media time from which output will begin, or {@link C#TIME_UNSET} if the * whole chunk should be output. - * @param chunkIndex The index of the chunk. + * @param chunkIndex The index of the chunk, or {@link C#INDEX_UNSET} if it is not known. * @param chunkCount The number of chunks in the underlying media that are spanned by this * instance. Normally equal to one, but may be larger if multiple chunks as defined by the * underlying media are being merged into a single load. @@ -94,11 +97,6 @@ public class ContainerMediaChunk extends BaseMediaChunk { return loadCompleted; } - @Override - public final long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override @@ -106,20 +104,15 @@ public class ContainerMediaChunk extends BaseMediaChunk { loadCanceled = true; } - @Override - public final boolean isLoadCanceled() { - return loadCanceled; - } - @SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (bytesLoaded == 0) { + if (nextLoadPosition == 0) { // Configure the output and set it as the target for the extractor wrapper. BaseMediaChunkOutput output = getOutput(); output.setSampleOffsetUs(sampleOffsetUs); @@ -131,11 +124,11 @@ public class ContainerMediaChunk extends BaseMediaChunk { Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, null); + result = extractor.read(input, DUMMY_POSITION_HOLDER); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = input.getPosition() - dataSpec.absoluteStreamPosition; } } finally { Util.closeQuietly(dataSource); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/DataChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/DataChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java index 99e95a709..7ea2521eb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/DataChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.Arrays; @@ -32,7 +32,6 @@ public abstract class DataChunk extends Chunk { private static final int READ_GRANULARITY = 16 * 1024; private byte[] data; - private int limit; private volatile boolean loadCanceled; @@ -63,11 +62,6 @@ public abstract class DataChunk extends Chunk { return data; } - @Override - public long bytesLoaded() { - return limit; - } - // Loadable implementation @Override @@ -75,19 +69,14 @@ public abstract class DataChunk extends Chunk { loadCanceled = true; } - @Override - public final boolean isLoadCanceled() { - return loadCanceled; - } - @Override public final void load() throws IOException, InterruptedException { try { dataSource.open(dataSpec); - limit = 0; + int limit = 0; int bytesRead = 0; while (bytesRead != C.RESULT_END_OF_INPUT && !loadCanceled) { - maybeExpandData(); + maybeExpandData(limit); bytesRead = dataSource.read(data, limit, READ_GRANULARITY); if (bytesRead != -1) { limit += bytesRead; @@ -111,7 +100,7 @@ public abstract class DataChunk extends Chunk { */ protected abstract void consume(byte[] data, int limit) throws IOException; - private void maybeExpandData() { + private void maybeExpandData(int limit) { if (data == null) { data = new byte[READ_GRANULARITY]; } else if (data.length < limit + READ_GRANULARITY) { @@ -120,5 +109,4 @@ public abstract class DataChunk extends Chunk { data = Arrays.copyOf(data, data.length + READ_GRANULARITY); } } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/InitializationChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/InitializationChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java index ed75f6224..d5c0d6f30 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/InitializationChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java @@ -13,18 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.DefaultExtractorInput; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** @@ -32,9 +33,11 @@ import java.io.IOException; */ public final class InitializationChunk extends Chunk { + private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); + private final ChunkExtractorWrapper extractorWrapper; - private volatile int bytesLoaded; + private long nextLoadPosition; private volatile boolean loadCanceled; /** @@ -57,11 +60,6 @@ public final class InitializationChunk extends Chunk { this.extractorWrapper = extractorWrapper; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override @@ -69,20 +67,15 @@ public final class InitializationChunk extends Chunk { loadCanceled = true; } - @Override - public boolean isLoadCanceled() { - return loadCanceled; - } - @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (bytesLoaded == 0) { + if (nextLoadPosition == 0) { extractorWrapper.init(/* trackOutputProvider= */ null, C.TIME_UNSET); } // Load and decode the initialization data. @@ -90,11 +83,11 @@ public final class InitializationChunk extends Chunk { Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, null); + result = extractor.read(input, DUMMY_POSITION_HOLDER); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = input.getPosition() - dataSpec.absoluteStreamPosition; } } finally { Util.closeQuietly(dataSource); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/MediaChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunk.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/MediaChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunk.java index bbabf5ac3..9626f4b03 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/MediaChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunk.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; /** * An abstract base class for {@link Chunk}s that contain media samples. */ public abstract class MediaChunk extends Chunk { - /** The chunk index. */ + /** The chunk index, or {@link C#INDEX_UNSET} if it is not known. */ public final long chunkIndex; /** @@ -37,7 +37,7 @@ public abstract class MediaChunk extends Chunk { * @param trackSelectionData See {@link #trackSelectionData}. * @param startTimeUs The start time of the media contained by the chunk, in microseconds. * @param endTimeUs The end time of the media contained by the chunk, in microseconds. - * @param chunkIndex The index of the chunk. + * @param chunkIndex The index of the chunk, or {@link C#INDEX_UNSET} if it is not known. */ public MediaChunk( DataSource dataSource, @@ -54,9 +54,9 @@ public abstract class MediaChunk extends Chunk { this.chunkIndex = chunkIndex; } - /** Returns the next chunk index. */ + /** Returns the next chunk index or {@link C#INDEX_UNSET} if it is not known. */ public long getNextChunkIndex() { - return chunkIndex + 1; + return chunkIndex != C.INDEX_UNSET ? chunkIndex + 1 : C.INDEX_UNSET; } /** diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunkIterator.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunkIterator.java new file mode 100755 index 000000000..71d8940e2 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/MediaChunkIterator.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.chunk; + +import com.google.android.exoplayer2.upstream.DataSpec; +import java.util.NoSuchElementException; + +/** + * Iterator for media chunk sequences. + * + *

    The iterator initially points in front of the first available element. The first call to + * {@link #next()} moves the iterator to the first element. Check the return value of {@link + * #next()} or {@link #isEnded()} to determine whether the iterator reached the end of the available + * data. + */ +public interface MediaChunkIterator { + + /** An empty media chunk iterator without available data. */ + MediaChunkIterator EMPTY = + new MediaChunkIterator() { + @Override + public boolean isEnded() { + return true; + } + + @Override + public boolean next() { + return false; + } + + @Override + public DataSpec getDataSpec() { + throw new NoSuchElementException(); + } + + @Override + public long getChunkStartTimeUs() { + throw new NoSuchElementException(); + } + + @Override + public long getChunkEndTimeUs() { + throw new NoSuchElementException(); + } + }; + + /** Returns whether the iteration has reached the end of the available data. */ + boolean isEnded(); + + /** + * Moves the iterator to the next media chunk. + * + *

    Check the return value or {@link #isEnded()} to determine whether the iterator reached the + * end of the available data. + * + * @return Whether the iterator points to a media chunk with available data. + */ + boolean next(); + + /** + * Returns the {@link DataSpec} used to load the media chunk. + * + * @throws java.util.NoSuchElementException If the method is called before the first call to + * {@link #next()} or when {@link #isEnded()} is true. + */ + DataSpec getDataSpec(); + + /** + * Returns the media start time of the chunk, in microseconds. + * + * @throws java.util.NoSuchElementException If the method is called before the first call to + * {@link #next()} or when {@link #isEnded()} is true. + */ + long getChunkStartTimeUs(); + + /** + * Returns the media end time of the chunk, in microseconds. + * + * @throws java.util.NoSuchElementException If the method is called before the first call to + * {@link #next()} or when {@link #isEnded()} is true. + */ + long getChunkEndTimeUs(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/SingleSampleMediaChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/SingleSampleMediaChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java index 0b06f3b61..2c00c7690 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/chunk/SingleSampleMediaChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.chunk; +package com.google.android.exoplayer2.source.chunk; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.DefaultExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** @@ -33,9 +33,8 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { private final int trackType; private final Format sampleFormat; - private volatile int bytesLoaded; - private volatile boolean loadCanceled; - private volatile boolean loadCompleted; + private long nextLoadPosition; + private boolean loadCompleted; /** * @param dataSource The source from which the data should be loaded. @@ -45,7 +44,7 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { * @param trackSelectionData See {@link #trackSelectionData}. * @param startTimeUs The start time of the media contained by the chunk, in microseconds. * @param endTimeUs The end time of the media contained by the chunk, in microseconds. - * @param chunkIndex The index of the chunk. + * @param chunkIndex The index of the chunk, or {@link C#INDEX_UNSET} if it is not known. * @param trackType The type of the chunk. Typically one of the {@link C} {@code TRACK_TYPE_*} * constants. * @param sampleFormat The {@link Format} of the sample in the chunk. @@ -81,34 +80,25 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { return loadCompleted; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override public void cancelLoad() { - loadCanceled = true; - } - - @Override - public boolean isLoadCanceled() { - return loadCanceled; + // Do nothing. } @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. long length = dataSource.open(loadDataSpec); if (length != C.LENGTH_UNSET) { - length += bytesLoaded; + length += nextLoadPosition; } - ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, bytesLoaded, length); + ExtractorInput extractorInput = + new DefaultExtractorInput(dataSource, nextLoadPosition, length); BaseMediaChunkOutput output = getOutput(); output.setSampleOffsetUs(0); TrackOutput trackOutput = output.track(0, trackType); @@ -116,10 +106,10 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { // Load the sample data. int result = 0; while (result != C.RESULT_END_OF_INPUT) { - bytesLoaded += result; + nextLoadPosition += result; result = trackOutput.sampleData(extractorInput, Integer.MAX_VALUE, true); } - int sampleSize = bytesLoaded; + int sampleSize = (int) nextLoadPosition; trackOutput.sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); } finally { Util.closeQuietly(dataSource); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java index fa4f85a0b..c6cdc88f2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import android.os.SystemClock; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkSource; -import org.telegram.messenger.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.source.chunk.ChunkSource; +import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; /** * An {@link ChunkSource} for DASH streams. @@ -44,6 +45,8 @@ public interface DashChunkSource extends ChunkSource { * message track. * @param enableCea608Track Whether the chunks generated by the source may output a CEA-608 * track. + * @param transferListener The transfer listener which should be informed of any data transfers. + * May be null if no listener is available. * @return The created {@link DashChunkSource}. */ DashChunkSource createDashChunkSource( @@ -56,7 +59,8 @@ public interface DashChunkSource extends ChunkSource { long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, boolean enableCea608Track, - @Nullable PlayerTrackEmsgHandler playerEmsgHandler); + @Nullable PlayerTrackEmsgHandler playerEmsgHandler, + @Nullable TransferListener transferListener); } /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashManifestStaleException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashManifestStaleException.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashManifestStaleException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashManifestStaleException.java index 3a0f0a9d7..7d946cb10 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashManifestStaleException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashManifestStaleException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 925e9d0f5..a22fd5ab2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -13,37 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import android.support.annotation.IntDef; +import android.support.annotation.Nullable; import android.util.Pair; -import android.util.SparseArray; import android.util.SparseIntArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.EmptySampleStream; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkSampleStream; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream; -import org.telegram.messenger.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCallback; -import org.telegram.messenger.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; -import org.telegram.messenger.exoplayer2.source.dash.manifest.AdaptationSet; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Descriptor; -import org.telegram.messenger.exoplayer2.source.dash.manifest.EventStream; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Period; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Representation; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.EmptySampleStream; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.chunk.ChunkSampleStream; +import com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream; +import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCallback; +import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; +import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.Descriptor; +import com.google.android.exoplayer2.source.dash.manifest.EventStream; +import com.google.android.exoplayer2.source.dash.manifest.Period; +import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -60,8 +61,8 @@ import java.util.List; /* package */ final int id; private final DashChunkSource.Factory chunkSourceFactory; + private final @Nullable TransferListener transferListener; private final int minLoadableRetryCount; - private final EventDispatcher eventDispatcher; private final long elapsedRealtimeOffset; private final LoaderErrorThrower manifestLoaderErrorThrower; private final Allocator allocator; @@ -72,7 +73,8 @@ import java.util.List; private final IdentityHashMap, PlayerTrackEmsgHandler> trackEmsgHandlerBySampleStream; - private Callback callback; + private EventDispatcher eventDispatcher; + private @Nullable Callback callback; private ChunkSampleStream[] sampleStreams; private EventSampleStream[] eventSampleStreams; private SequenceableLoader compositeSequenceableLoader; @@ -86,6 +88,7 @@ import java.util.List; DashManifest manifest, int periodIndex, DashChunkSource.Factory chunkSourceFactory, + @Nullable TransferListener transferListener, int minLoadableRetryCount, EventDispatcher eventDispatcher, long elapsedRealtimeOffset, @@ -97,6 +100,7 @@ import java.util.List; this.manifest = manifest; this.periodIndex = periodIndex; this.chunkSourceFactory = chunkSourceFactory; + this.transferListener = transferListener; this.minLoadableRetryCount = minLoadableRetryCount; this.eventDispatcher = eventDispatcher; this.elapsedRealtimeOffset = elapsedRealtimeOffset; @@ -126,6 +130,13 @@ import java.util.List; */ public void updateManifest(DashManifest manifest, int periodIndex) { this.manifest = manifest; + if (this.periodIndex != periodIndex) { + eventDispatcher = + eventDispatcher.withParameters( + /* windowIndex= */ 0, + eventDispatcher.mediaPeriodId.copyWithPeriodIndex(periodIndex), + manifest.getPeriod(periodIndex).startMs); + } this.periodIndex = periodIndex; playerEmsgHandler.updateManifest(manifest); if (sampleStreams != null) { @@ -150,6 +161,7 @@ import java.util.List; for (ChunkSampleStream sampleStream : sampleStreams) { sampleStream.release(this); } + callback = null; eventDispatcher.mediaPeriodReleased(); } @@ -184,126 +196,34 @@ import java.util.List; @Override public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { - SparseArray> primarySampleStreams = new SparseArray<>(); - List eventSampleStreamList = new ArrayList<>(); + int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections); + releaseDisabledStreams(selections, mayRetainStreamFlags, streams); + releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex); + selectNewStreams( + selections, streams, streamResetFlags, positionUs, streamIndexToTrackGroupIndex); - selectPrimarySampleStreams(selections, mayRetainStreamFlags, streams, streamResetFlags, - positionUs, primarySampleStreams); - selectEventSampleStreams(selections, mayRetainStreamFlags, streams, - streamResetFlags, eventSampleStreamList); - selectEmbeddedSampleStreams(selections, mayRetainStreamFlags, streams, streamResetFlags, - positionUs, primarySampleStreams); - - sampleStreams = newSampleStreamArray(primarySampleStreams.size()); - for (int i = 0; i < sampleStreams.length; i++) { - sampleStreams[i] = primarySampleStreams.valueAt(i); + ArrayList> sampleStreamList = new ArrayList<>(); + ArrayList eventSampleStreamList = new ArrayList<>(); + for (SampleStream sampleStream : streams) { + if (sampleStream instanceof ChunkSampleStream) { + @SuppressWarnings("unchecked") + ChunkSampleStream stream = + (ChunkSampleStream) sampleStream; + sampleStreamList.add(stream); + } else if (sampleStream instanceof EventSampleStream) { + eventSampleStreamList.add((EventSampleStream) sampleStream); + } } + sampleStreams = newSampleStreamArray(sampleStreamList.size()); + sampleStreamList.toArray(sampleStreams); eventSampleStreams = new EventSampleStream[eventSampleStreamList.size()]; eventSampleStreamList.toArray(eventSampleStreams); + compositeSequenceableLoader = compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams); return positionUs; } - private void selectPrimarySampleStreams( - TrackSelection[] selections, - boolean[] mayRetainStreamFlags, - SampleStream[] streams, - boolean[] streamResetFlags, - long positionUs, - SparseArray> primarySampleStreams) { - for (int i = 0; i < selections.length; i++) { - if (streams[i] instanceof ChunkSampleStream) { - @SuppressWarnings("unchecked") - ChunkSampleStream stream = (ChunkSampleStream) streams[i]; - if (selections[i] == null || !mayRetainStreamFlags[i]) { - stream.release(this); - streams[i] = null; - } else { - int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - primarySampleStreams.put(trackGroupIndex, stream); - } - } - - if (streams[i] == null && selections[i] != null) { - int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; - if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_PRIMARY) { - ChunkSampleStream stream = buildSampleStream(trackGroupInfo, - selections[i], positionUs); - primarySampleStreams.put(trackGroupIndex, stream); - streams[i] = stream; - streamResetFlags[i] = true; - } - } - } - } - - private void selectEventSampleStreams(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, - List eventSampleStreamsList) { - for (int i = 0; i < selections.length; i++) { - if (streams[i] instanceof EventSampleStream) { - EventSampleStream stream = (EventSampleStream) streams[i]; - if (selections[i] == null || !mayRetainStreamFlags[i]) { - streams[i] = null; - } else { - eventSampleStreamsList.add(stream); - } - } - - if (streams[i] == null && selections[i] != null) { - int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; - if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_MANIFEST_EVENTS) { - EventStream eventStream = eventStreams.get(trackGroupInfo.eventStreamGroupIndex); - Format format = selections[i].getTrackGroup().getFormat(0); - EventSampleStream stream = new EventSampleStream(eventStream, format, manifest.dynamic); - streams[i] = stream; - streamResetFlags[i] = true; - eventSampleStreamsList.add(stream); - } - } - } - } - - private void selectEmbeddedSampleStreams( - TrackSelection[] selections, - boolean[] mayRetainStreamFlags, - SampleStream[] streams, - boolean[] streamResetFlags, - long positionUs, - SparseArray> primarySampleStreams) { - for (int i = 0; i < selections.length; i++) { - if ((streams[i] instanceof EmbeddedSampleStream || streams[i] instanceof EmptySampleStream) - && (selections[i] == null || !mayRetainStreamFlags[i])) { - // The stream is for an embedded track and is either no longer selected or needs replacing. - releaseIfEmbeddedSampleStream(streams[i]); - streams[i] = null; - } - // We need to consider replacing the stream even if it's non-null because the primary stream - // may have been replaced, selected or deselected. - if (selections[i] != null) { - int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; - if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_EMBEDDED) { - ChunkSampleStream primaryStream = primarySampleStreams.get( - trackGroupInfo.primaryTrackGroupIndex); - SampleStream stream = streams[i]; - boolean mayRetainStream = primaryStream == null ? stream instanceof EmptySampleStream - : (stream instanceof EmbeddedSampleStream - && ((EmbeddedSampleStream) stream).parent == primaryStream); - if (!mayRetainStream) { - releaseIfEmbeddedSampleStream(stream); - streams[i] = primaryStream == null ? new EmptySampleStream() - : primaryStream.selectEmbeddedTrack(positionUs, trackGroupInfo.trackType); - streamResetFlags[i] = true; - } - } - } - } - } - @Override public void discardBuffer(long positionUs, boolean toKeyframe) { for (ChunkSampleStream sampleStream : sampleStreams) { @@ -370,6 +290,124 @@ import java.util.List; // Internal methods. + private int[] getStreamIndexToTrackGroupIndex(TrackSelection[] selections) { + int[] streamIndexToTrackGroupIndex = new int[selections.length]; + for (int i = 0; i < selections.length; i++) { + if (selections[i] != null) { + streamIndexToTrackGroupIndex[i] = trackGroups.indexOf(selections[i].getTrackGroup()); + } else { + streamIndexToTrackGroupIndex[i] = C.INDEX_UNSET; + } + } + return streamIndexToTrackGroupIndex; + } + + private void releaseDisabledStreams( + TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams) { + for (int i = 0; i < selections.length; i++) { + if (selections[i] == null || !mayRetainStreamFlags[i]) { + if (streams[i] instanceof ChunkSampleStream) { + @SuppressWarnings("unchecked") + ChunkSampleStream stream = + (ChunkSampleStream) streams[i]; + stream.release(this); + } else if (streams[i] instanceof EmbeddedSampleStream) { + ((EmbeddedSampleStream) streams[i]).release(); + } + streams[i] = null; + } + } + } + + private void releaseOrphanEmbeddedStreams( + TrackSelection[] selections, SampleStream[] streams, int[] streamIndexToTrackGroupIndex) { + for (int i = 0; i < selections.length; i++) { + if (streams[i] instanceof EmptySampleStream || streams[i] instanceof EmbeddedSampleStream) { + // We need to release an embedded stream if the corresponding primary stream is released. + int primaryStreamIndex = getPrimaryStreamIndex(i, streamIndexToTrackGroupIndex); + boolean mayRetainStream; + if (primaryStreamIndex == C.INDEX_UNSET) { + // If the corresponding primary stream is not selected, we may retain an existing + // EmptySampleStream. + mayRetainStream = streams[i] instanceof EmptySampleStream; + } else { + // If the corresponding primary stream is selected, we may retain the embedded stream if + // the stream's parent still matches. + mayRetainStream = + (streams[i] instanceof EmbeddedSampleStream) + && ((EmbeddedSampleStream) streams[i]).parent == streams[primaryStreamIndex]; + } + if (!mayRetainStream) { + if (streams[i] instanceof EmbeddedSampleStream) { + ((EmbeddedSampleStream) streams[i]).release(); + } + streams[i] = null; + } + } + } + } + + private void selectNewStreams( + TrackSelection[] selections, + SampleStream[] streams, + boolean[] streamResetFlags, + long positionUs, + int[] streamIndexToTrackGroupIndex) { + // Create newly selected primary and event streams. + for (int i = 0; i < selections.length; i++) { + if (streams[i] == null && selections[i] != null) { + streamResetFlags[i] = true; + int trackGroupIndex = streamIndexToTrackGroupIndex[i]; + TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; + if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_PRIMARY) { + streams[i] = buildSampleStream(trackGroupInfo, selections[i], positionUs); + } else if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_MANIFEST_EVENTS) { + EventStream eventStream = eventStreams.get(trackGroupInfo.eventStreamGroupIndex); + Format format = selections[i].getTrackGroup().getFormat(0); + streams[i] = new EventSampleStream(eventStream, format, manifest.dynamic); + } + } + } + // Create newly selected embedded streams from the corresponding primary stream. Note that this + // second pass is needed because the primary stream may not have been created yet in a first + // pass if the index of the primary stream is greater than the index of the embedded stream. + for (int i = 0; i < selections.length; i++) { + if (streams[i] == null && selections[i] != null) { + int trackGroupIndex = streamIndexToTrackGroupIndex[i]; + TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; + if (trackGroupInfo.trackGroupCategory == TrackGroupInfo.CATEGORY_EMBEDDED) { + int primaryStreamIndex = getPrimaryStreamIndex(i, streamIndexToTrackGroupIndex); + if (primaryStreamIndex == C.INDEX_UNSET) { + // If an embedded track is selected without the corresponding primary track, create an + // empty sample stream instead. + streams[i] = new EmptySampleStream(); + } else { + streams[i] = + ((ChunkSampleStream) streams[primaryStreamIndex]) + .selectEmbeddedTrack(positionUs, trackGroupInfo.trackType); + } + } + } + } + } + + private int getPrimaryStreamIndex(int embeddedStreamIndex, int[] streamIndexToTrackGroupIndex) { + int embeddedTrackGroupIndex = streamIndexToTrackGroupIndex[embeddedStreamIndex]; + if (embeddedTrackGroupIndex == C.INDEX_UNSET) { + return C.INDEX_UNSET; + } + int primaryTrackGroupIndex = trackGroupInfos[embeddedTrackGroupIndex].primaryTrackGroupIndex; + for (int i = 0; i < streamIndexToTrackGroupIndex.length; i++) { + int trackGroupIndex = streamIndexToTrackGroupIndex[i]; + if (trackGroupIndex == primaryTrackGroupIndex + && trackGroupInfos[trackGroupIndex].trackGroupCategory + == TrackGroupInfo.CATEGORY_PRIMARY) { + return i; + } + } + return C.INDEX_UNSET; + } + private static Pair buildTrackGroups( List adaptationSets, List eventStreams) { int[][] groupedAdaptationSetIndices = getGroupedAdaptationSetIndices(adaptationSets); @@ -560,7 +598,8 @@ import java.util.List; elapsedRealtimeOffset, enableEventMessageTrack, enableCea608Track, - trackPlayerEmsgHandler); + trackPlayerEmsgHandler, + transferListener); ChunkSampleStream stream = new ChunkSampleStream<>( trackGroupInfo.trackType, @@ -622,12 +661,6 @@ import java.util.List; return new ChunkSampleStream[length]; } - private static void releaseIfEmbeddedSampleStream(SampleStream sampleStream) { - if (sampleStream instanceof EmbeddedSampleStream) { - ((EmbeddedSampleStream) sampleStream).release(); - } - } - private static final class TrackGroupInfo { @Retention(RetentionPolicy.SOURCE) diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index f40cfab9f..9e1d3c783 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import android.net.Uri; import android.os.Handler; @@ -22,31 +22,34 @@ import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.BaseMediaSource; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.ads.AdsMediaSource; -import org.telegram.messenger.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCallback; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifestParser; -import org.telegram.messenger.exoplayer2.source.dash.manifest.UtcTimingElement; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.BaseMediaSource; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.ads.AdsMediaSource; +import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCallback; +import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; +import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -76,9 +79,20 @@ public final class DashMediaSource extends BaseMediaSource { private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private int minLoadableRetryCount; private long livePresentationDelayMs; + private boolean livePresentationDelayOverridesManifest; private boolean isCreateCalled; private @Nullable Object tag; + /** + * Creates a new factory for {@link DashMediaSource}s. + * + * @param dataSourceFactory A factory for {@link DataSource} instances that will be used to load + * manifest and media data. + */ + public Factory(DataSource.Factory dataSourceFactory) { + this(new DefaultDashChunkSource.Factory(dataSourceFactory), dataSourceFactory); + } + /** * Creates a new factory for {@link DashMediaSource}s. * @@ -94,14 +108,14 @@ public final class DashMediaSource extends BaseMediaSource { this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory); this.manifestDataSourceFactory = manifestDataSourceFactory; minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT; - livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS; + livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS; compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory(); } /** * Sets a tag for the media source which will be published in the {@link - * org.telegram.messenger.exoplayer2.Timeline} of the source as {@link - * org.telegram.messenger.exoplayer2.Timeline.Window#tag}. + * com.google.android.exoplayer2.Timeline} of the source as {@link + * com.google.android.exoplayer2.Timeline.Window#tag}. * * @param tag A tag for the media source. * @return This factory, for convenience. @@ -127,21 +141,36 @@ public final class DashMediaSource extends BaseMediaSource { return this; } + /** @deprecated Use {@link #setLivePresentationDelayMs(long, boolean)}. */ + @Deprecated + @SuppressWarnings("deprecation") + public Factory setLivePresentationDelayMs(long livePresentationDelayMs) { + if (livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS) { + return setLivePresentationDelayMs(DEFAULT_LIVE_PRESENTATION_DELAY_MS, false); + } else { + return setLivePresentationDelayMs(livePresentationDelayMs, true); + } + } + /** * Sets the duration in milliseconds by which the default start position should precede the end - * of the live window for live playbacks. The default value is {@link - * #DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS}. + * of the live window for live playbacks. The {@code overridesManifest} parameter specifies + * whether the value is used in preference to one in the manifest, if present. The default value + * is {@link #DEFAULT_LIVE_PRESENTATION_DELAY_MS}, and by default {@code overridesManifest} is + * false. * * @param livePresentationDelayMs For live playbacks, the duration in milliseconds by which the - * default start position should precede the end of the live window. Use {@link - * #DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS} to use the value specified by the - * manifest, if present. + * default start position should precede the end of the live window. + * @param overridesManifest Whether the value is used in preference to one in the manifest, if + * present. * @return This factory, for convenience. * @throws IllegalStateException If one of the {@code create} methods has already been called. */ - public Factory setLivePresentationDelayMs(long livePresentationDelayMs) { + public Factory setLivePresentationDelayMs( + long livePresentationDelayMs, boolean overridesManifest) { Assertions.checkState(!isCreateCalled); this.livePresentationDelayMs = livePresentationDelayMs; + this.livePresentationDelayOverridesManifest = overridesManifest; return this; } @@ -198,6 +227,7 @@ public final class DashMediaSource extends BaseMediaSource { compositeSequenceableLoaderFactory, minLoadableRetryCount, livePresentationDelayMs, + livePresentationDelayOverridesManifest, tag); } @@ -238,6 +268,7 @@ public final class DashMediaSource extends BaseMediaSource { compositeSequenceableLoaderFactory, minLoadableRetryCount, livePresentationDelayMs, + livePresentationDelayOverridesManifest, tag); } @@ -267,18 +298,18 @@ public final class DashMediaSource extends BaseMediaSource { * The default minimum number of times to retry loading data prior to failing. */ public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; + /** - * A constant indicating that the presentation delay for live streams should be set to - * {@link DashManifest#suggestedPresentationDelayMs} if specified by the manifest, or - * {@link #DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS} otherwise. The presentation delay is the - * duration by which the default start position precedes the end of the live window. + * The default presentation delay for live streams. The presentation delay is the duration by + * which the default start position precedes the end of the live window. */ - public static final long DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS = -1; - /** - * A fixed default presentation delay for live streams. The presentation delay is the duration - * by which the default start position precedes the end of the live window. - */ - public static final long DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS = 30000; + public static final long DEFAULT_LIVE_PRESENTATION_DELAY_MS = 30000; + /** @deprecated Use {@link #DEFAULT_LIVE_PRESENTATION_DELAY_MS}. */ + @Deprecated + public static final long DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS = + DEFAULT_LIVE_PRESENTATION_DELAY_MS; + /** @deprecated Use of this parameter is no longer necessary. */ + @Deprecated public static final long DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS = -1; /** * The interval in milliseconds between invocations of {@link @@ -299,6 +330,7 @@ public final class DashMediaSource extends BaseMediaSource { private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private final int minLoadableRetryCount; private final long livePresentationDelayMs; + private final boolean livePresentationDelayOverridesManifest; private final EventDispatcher manifestEventDispatcher; private final ParsingLoadable.Parser manifestParser; private final ManifestCallback manifestCallback; @@ -312,6 +344,7 @@ public final class DashMediaSource extends BaseMediaSource { private DataSource dataSource; private Loader loader; + private @Nullable TransferListener mediaTransferListener; private IOException manifestFatalError; private Handler handler; @@ -340,6 +373,7 @@ public final class DashMediaSource extends BaseMediaSource { * @deprecated Use {@link Factory} instead. */ @Deprecated + @SuppressWarnings("deprecation") public DashMediaSource( DashManifest manifest, DashChunkSource.Factory chunkSourceFactory, @@ -374,7 +408,8 @@ public final class DashMediaSource extends BaseMediaSource { chunkSourceFactory, new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount, - DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS, + DEFAULT_LIVE_PRESENTATION_DELAY_MS, + /* livePresentationDelayOverridesManifest= */ false, /* tag= */ null); if (eventHandler != null && eventListener != null) { addEventListener(eventHandler, eventListener); @@ -394,6 +429,7 @@ public final class DashMediaSource extends BaseMediaSource { * @deprecated Use {@link Factory} instead. */ @Deprecated + @SuppressWarnings("deprecation") public DashMediaSource( Uri manifestUri, DataSource.Factory manifestDataSourceFactory, @@ -423,6 +459,7 @@ public final class DashMediaSource extends BaseMediaSource { * @deprecated Use {@link Factory} instead. */ @Deprecated + @SuppressWarnings("deprecation") public DashMediaSource( Uri manifestUri, DataSource.Factory manifestDataSourceFactory, @@ -431,8 +468,15 @@ public final class DashMediaSource extends BaseMediaSource { long livePresentationDelayMs, Handler eventHandler, MediaSourceEventListener eventListener) { - this(manifestUri, manifestDataSourceFactory, new DashManifestParser(), chunkSourceFactory, - minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener); + this( + manifestUri, + manifestDataSourceFactory, + new DashManifestParser(), + chunkSourceFactory, + minLoadableRetryCount, + livePresentationDelayMs, + eventHandler, + eventListener); } /** @@ -454,6 +498,7 @@ public final class DashMediaSource extends BaseMediaSource { * @deprecated Use {@link Factory} instead. */ @Deprecated + @SuppressWarnings("deprecation") public DashMediaSource( Uri manifestUri, DataSource.Factory manifestDataSourceFactory, @@ -471,7 +516,10 @@ public final class DashMediaSource extends BaseMediaSource { chunkSourceFactory, new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount, - livePresentationDelayMs, + livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS + ? DEFAULT_LIVE_PRESENTATION_DELAY_MS + : livePresentationDelayMs, + livePresentationDelayMs != DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS, /* tag= */ null); if (eventHandler != null && eventListener != null) { addEventListener(eventHandler, eventListener); @@ -487,6 +535,7 @@ public final class DashMediaSource extends BaseMediaSource { CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, int minLoadableRetryCount, long livePresentationDelayMs, + boolean livePresentationDelayOverridesManifest, @Nullable Object tag) { this.initialManifestUri = manifestUri; this.manifest = manifest; @@ -496,6 +545,7 @@ public final class DashMediaSource extends BaseMediaSource { this.chunkSourceFactory = chunkSourceFactory; this.minLoadableRetryCount = minLoadableRetryCount; this.livePresentationDelayMs = livePresentationDelayMs; + this.livePresentationDelayOverridesManifest = livePresentationDelayOverridesManifest; this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory; this.tag = tag; sideloadedManifest = manifest != null; @@ -543,7 +593,11 @@ public final class DashMediaSource extends BaseMediaSource { // MediaSource implementation. @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + this.mediaTransferListener = mediaTransferListener; if (sideloadedManifest) { processManifest(false); } else { @@ -570,6 +624,7 @@ public final class DashMediaSource extends BaseMediaSource { manifest, periodIndex, chunkSourceFactory, + mediaTransferListener, minLoadableRetryCount, periodEventDispatcher, elapsedRealtimeOffsetMs, @@ -637,6 +692,7 @@ public final class DashMediaSource extends BaseMediaSource { long elapsedRealtimeMs, long loadDurationMs) { manifestEventDispatcher.loadCompleted( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -698,7 +754,9 @@ public final class DashMediaSource extends BaseMediaSource { synchronized (manifestUriLock) { // This condition checks that replaceManifestUri wasn't called between the start and end of // this load. If it was, we ignore the manifest location and prefer the manual replacement. - if (loadable.dataSpec.uri == manifestUri) { + @SuppressWarnings("ReferenceEquality") + boolean isSameUriInstance = loadable.dataSpec.uri == manifestUri; + if (isSameUriInstance) { manifestUri = manifest.location; } } @@ -716,8 +774,7 @@ public final class DashMediaSource extends BaseMediaSource { } } - /* package */ @Loader.RetryAction - int onManifestLoadError( + /* package */ LoadErrorAction onManifestLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, @@ -725,6 +782,7 @@ public final class DashMediaSource extends BaseMediaSource { boolean isFatal = error instanceof ParserException; manifestEventDispatcher.loadError( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -738,6 +796,7 @@ public final class DashMediaSource extends BaseMediaSource { long elapsedRealtimeMs, long loadDurationMs) { manifestEventDispatcher.loadCompleted( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -745,14 +804,14 @@ public final class DashMediaSource extends BaseMediaSource { onUtcTimestampResolved(loadable.getResult() - elapsedRealtimeMs); } - /* package */ @Loader.RetryAction - int onUtcTimestampLoadError( + /* package */ LoadErrorAction onUtcTimestampLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { manifestEventDispatcher.loadError( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -767,6 +826,7 @@ public final class DashMediaSource extends BaseMediaSource { long loadDurationMs) { manifestEventDispatcher.loadCanceled( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -869,9 +929,9 @@ public final class DashMediaSource extends BaseMediaSource { long windowDefaultStartPositionUs = 0; if (manifest.dynamic) { long presentationDelayForManifestMs = livePresentationDelayMs; - if (presentationDelayForManifestMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS) { - presentationDelayForManifestMs = manifest.suggestedPresentationDelayMs != C.TIME_UNSET - ? manifest.suggestedPresentationDelayMs : DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS; + if (!livePresentationDelayOverridesManifest + && manifest.suggestedPresentationDelayMs != C.TIME_UNSET) { + presentationDelayForManifestMs = manifest.suggestedPresentationDelayMs; } // Snap the default position to the start of the segment containing it. windowDefaultStartPositionUs = windowDurationUs - C.msToUs(presentationDelayForManifestMs); @@ -954,7 +1014,8 @@ public final class DashMediaSource extends BaseMediaSource { private void startLoading(ParsingLoadable loadable, Loader.Callback> callback, int minRetryCount) { long elapsedRealtimeMs = loader.startLoading(loadable, callback, minRetryCount); - manifestEventDispatcher.loadStarted(loadable.dataSpec, loadable.type, elapsedRealtimeMs); + manifestEventDispatcher.loadStarted( + loadable.dataSpec, loadable.dataSpec.uri, loadable.type, elapsedRealtimeMs); } private long getNowUnixTimeUs() { @@ -968,14 +1029,31 @@ public final class DashMediaSource extends BaseMediaSource { private static final class PeriodSeekInfo { public static PeriodSeekInfo createPeriodSeekInfo( - org.telegram.messenger.exoplayer2.source.dash.manifest.Period period, long durationUs) { + com.google.android.exoplayer2.source.dash.manifest.Period period, long durationUs) { int adaptationSetCount = period.adaptationSets.size(); long availableStartTimeUs = 0; long availableEndTimeUs = Long.MAX_VALUE; boolean isIndexExplicit = false; boolean seenEmptyIndex = false; + + boolean haveAudioVideoAdaptationSets = false; for (int i = 0; i < adaptationSetCount; i++) { - DashSegmentIndex index = period.adaptationSets.get(i).representations.get(0).getIndex(); + int type = period.adaptationSets.get(i).type; + if (type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO) { + haveAudioVideoAdaptationSets = true; + break; + } + } + + for (int i = 0; i < adaptationSetCount; i++) { + AdaptationSet adaptationSet = period.adaptationSets.get(i); + // Exclude text adaptation sets from duration calculations, if we have at least one audio + // or video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029 + if (haveAudioVideoAdaptationSets && adaptationSet.type == C.TRACK_TYPE_TEXT) { + continue; + } + + DashSegmentIndex index = adaptationSet.representations.get(0).getIndex(); if (index == null) { return new PeriodSeekInfo(true, 0, durationUs); } @@ -1051,10 +1129,9 @@ public final class DashMediaSource extends BaseMediaSource { @Override public Period getPeriod(int periodIndex, Period period, boolean setIdentifiers) { - Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()); + Assertions.checkIndex(periodIndex, 0, getPeriodCount()); Object id = setIdentifiers ? manifest.getPeriod(periodIndex).id : null; - Object uid = setIdentifiers ? firstPeriodId - + Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()) : null; + Object uid = setIdentifiers ? (firstPeriodId + periodIndex) : null; return period.set(id, uid, 0, manifest.getPeriodDurationUs(periodIndex), C.msToUs(manifest.getPeriod(periodIndex).startMs - manifest.getPeriod(0).startMs) - offsetInFirstPeriodUs); @@ -1081,7 +1158,7 @@ public final class DashMediaSource extends BaseMediaSource { windowDefaultStartPositionUs, windowDurationUs, /* firstPeriodIndex= */ 0, - manifest.getPeriodCount() - 1, + /* lastPeriodIndex= */ getPeriodCount() - 1, offsetInFirstPeriodUs); } @@ -1091,8 +1168,8 @@ public final class DashMediaSource extends BaseMediaSource { return C.INDEX_UNSET; } int periodId = (int) uid; - return periodId < firstPeriodId || periodId >= firstPeriodId + getPeriodCount() - ? C.INDEX_UNSET : (periodId - firstPeriodId); + int periodIndex = periodId - firstPeriodId; + return periodIndex < 0 || periodIndex >= getPeriodCount() ? C.INDEX_UNSET : periodIndex; } private long getAdjustedWindowDefaultStartPositionUs(long defaultPositionProjectionUs) { @@ -1117,7 +1194,7 @@ public final class DashMediaSource extends BaseMediaSource { periodIndex++; periodDurationUs = manifest.getPeriodDurationUs(periodIndex); } - org.telegram.messenger.exoplayer2.source.dash.manifest.Period period = + com.google.android.exoplayer2.source.dash.manifest.Period period = manifest.getPeriod(periodIndex); int videoAdaptationSetIndex = period.getAdaptationSetIndex(C.TRACK_TYPE_VIDEO); if (videoAdaptationSetIndex == C.INDEX_UNSET) { @@ -1137,6 +1214,11 @@ public final class DashMediaSource extends BaseMediaSource { - defaultStartPositionInPeriodUs; } + @Override + public Object getUidOfPeriod(int periodIndex) { + Assertions.checkIndex(periodIndex, 0, getPeriodCount()); + return firstPeriodId + periodIndex; + } } private final class DefaultPlayerEmsgCallback implements PlayerEmsgCallback { @@ -1172,11 +1254,12 @@ public final class DashMediaSource extends BaseMediaSource { } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, - IOException error) { + IOException error, + int errorCount) { return onManifestLoadError(loadable, elapsedRealtimeMs, loadDurationMs, error); } @@ -1197,11 +1280,12 @@ public final class DashMediaSource extends BaseMediaSource { } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, - IOException error) { + IOException error, + int errorCount) { return onUtcTimestampLoadError(loadable, elapsedRealtimeMs, loadDurationMs, error); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashSegmentIndex.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashSegmentIndex.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashSegmentIndex.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashSegmentIndex.java index d2a8eb086..9d45bc726 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashSegmentIndex.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashSegmentIndex.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.source.dash.manifest.RangedUri; /** * Indexes the segments within a media stream. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java index c6d0278c5..743462bd8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java @@ -13,29 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.mkv.MatroskaExtractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkExtractorWrapper; -import org.telegram.messenger.exoplayer2.source.chunk.InitializationChunk; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifestParser; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Period; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Representation; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.InitializationChunk; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; +import com.google.android.exoplayer2.source.dash.manifest.Period; +import com.google.android.exoplayer2.source.dash.manifest.RangedUri; +import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.HttpDataSource; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; import java.util.List; @@ -54,7 +54,7 @@ public final class DashUtil { */ public static DashManifest loadManifest(DataSource dataSource, Uri uri) throws IOException { - return ParsingLoadable.load(dataSource, new DashManifestParser(), uri); + return ParsingLoadable.load(dataSource, new DashManifestParser(), uri, C.DATA_TYPE_MANIFEST); } /** @@ -89,7 +89,7 @@ public final class DashUtil { * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the {@link - * org.telegram.messenger.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @return the sample {@link Format} of the given representation. * @throws IOException Thrown when there is an error while loading. @@ -109,7 +109,7 @@ public final class DashUtil { * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the {@link - * org.telegram.messenger.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @return The {@link ChunkIndex} of the given representation, or null if no initialization or * index data exists. @@ -130,7 +130,7 @@ public final class DashUtil { * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the {@link - * org.telegram.messenger.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @param loadIndex Whether to load index data too. * @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashWrappingSegmentIndex.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashWrappingSegmentIndex.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashWrappingSegmentIndex.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashWrappingSegmentIndex.java index d9c73e922..3eca7892c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DashWrappingSegmentIndex.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DashWrappingSegmentIndex.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.source.dash.manifest.RangedUri; /** * An implementation of {@link DashSegmentIndex} that wraps a {@link ChunkIndex} parsed from a @@ -25,12 +25,15 @@ import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; public final class DashWrappingSegmentIndex implements DashSegmentIndex { private final ChunkIndex chunkIndex; + private final long timeOffsetUs; /** * @param chunkIndex The {@link ChunkIndex} to wrap. + * @param timeOffsetUs An offset to subtract from the times in the wrapped index, in microseconds. */ - public DashWrappingSegmentIndex(ChunkIndex chunkIndex) { + public DashWrappingSegmentIndex(ChunkIndex chunkIndex, long timeOffsetUs) { this.chunkIndex = chunkIndex; + this.timeOffsetUs = timeOffsetUs; } @Override @@ -45,7 +48,7 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex { @Override public long getTimeUs(long segmentNum) { - return chunkIndex.timesUs[(int) segmentNum]; + return chunkIndex.timesUs[(int) segmentNum] - timeOffsetUs; } @Override @@ -61,7 +64,7 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex { @Override public long getSegmentNum(long timeUs, long periodDurationUs) { - return chunkIndex.getChunkIndex(timeUs); + return chunkIndex.getChunkIndex(timeUs + timeOffsetUs); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DefaultDashChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java similarity index 69% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DefaultDashChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index 8b414296e..7aea84f0c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -13,42 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; import android.net.Uri; import android.os.SystemClock; +import android.support.annotation.CheckResult; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.extractor.mkv.MatroskaExtractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import org.telegram.messenger.exoplayer2.extractor.rawcc.RawCcExtractor; -import org.telegram.messenger.exoplayer2.source.BehindLiveWindowException; -import org.telegram.messenger.exoplayer2.source.chunk.Chunk; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkExtractorWrapper; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkHolder; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; -import org.telegram.messenger.exoplayer2.source.chunk.ContainerMediaChunk; -import org.telegram.messenger.exoplayer2.source.chunk.InitializationChunk; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; -import org.telegram.messenger.exoplayer2.source.chunk.SingleSampleMediaChunk; -import org.telegram.messenger.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; -import org.telegram.messenger.exoplayer2.source.dash.manifest.AdaptationSet; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Representation; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.rawcc.RawCcExtractor; +import com.google.android.exoplayer2.source.BehindLiveWindowException; +import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.ChunkHolder; +import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; +import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk; +import com.google.android.exoplayer2.source.chunk.InitializationChunk; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; +import com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk; +import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler; +import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.RangedUri; +import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -84,8 +88,12 @@ public class DefaultDashChunkSource implements DashChunkSource { long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, boolean enableCea608Track, - @Nullable PlayerTrackEmsgHandler playerEmsgHandler) { + @Nullable PlayerTrackEmsgHandler playerEmsgHandler, + @Nullable TransferListener transferListener) { DataSource dataSource = dataSourceFactory.createDataSource(); + if (transferListener != null) { + dataSource.addTransferListener(transferListener); + } return new DefaultDashChunkSource( manifestLoaderErrorThrower, manifest, @@ -209,7 +217,8 @@ public class DefaultDashChunkSource implements DashChunkSource { List representations = getRepresentations(); for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); - representationHolders[i].updateRepresentation(periodDurationUs, representation); + representationHolders[i] = + representationHolders[i].copyWithNewRepresentation(periodDurationUs, representation); } } catch (BehindLiveWindowException e) { fatalError = e; @@ -234,7 +243,10 @@ public class DefaultDashChunkSource implements DashChunkSource { } @Override - public void getNextChunk(MediaChunk previous, long playbackPositionUs, long loadPositionUs, + public void getNextChunk( + long playbackPositionUs, + long loadPositionUs, + List queue, ChunkHolder out) { if (fatalError != null) { return; @@ -307,11 +319,11 @@ public class DefaultDashChunkSource implements DashChunkSource { updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum); long segmentNum; - if (previous == null) { + if (queue.isEmpty()) { segmentNum = Util.constrainValue(representationHolder.getSegmentNum(loadPositionUs), firstAvailableSegmentNum, lastAvailableSegmentNum); } else { - segmentNum = previous.getNextChunkIndex(); + segmentNum = queue.get(queue.size() - 1).getNextChunkIndex(); if (segmentNum < firstAvailableSegmentNum) { // This is before the first chunk in the current manifest. fatalError = new BehindLiveWindowException(); @@ -328,7 +340,7 @@ public class DefaultDashChunkSource implements DashChunkSource { int maxSegmentCount = (int) Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1); - long seekTimeUs = previous == null ? loadPositionUs : C.TIME_UNSET; + long seekTimeUs = queue.isEmpty() ? loadPositionUs : C.TIME_UNSET; out.chunk = newMediaChunk( representationHolder, @@ -346,15 +358,19 @@ public class DefaultDashChunkSource implements DashChunkSource { public void onChunkLoadCompleted(Chunk chunk) { if (chunk instanceof InitializationChunk) { InitializationChunk initializationChunk = (InitializationChunk) chunk; - RepresentationHolder representationHolder = - representationHolders[trackSelection.indexOf(initializationChunk.trackFormat)]; + int trackIndex = trackSelection.indexOf(initializationChunk.trackFormat); + RepresentationHolder representationHolder = representationHolders[trackIndex]; // The null check avoids overwriting an index obtained from the manifest with one obtained // from the stream. If the manifest defines an index then the stream shouldn't, but in cases // where it does we should ignore it. if (representationHolder.segmentIndex == null) { SeekMap seekMap = representationHolder.extractorWrapper.getSeekMap(); if (seekMap != null) { - representationHolder.segmentIndex = new DashWrappingSegmentIndex((ChunkIndex) seekMap); + representationHolders[trackIndex] = + representationHolder.copyWithNewSegmentIndex( + new DashWrappingSegmentIndex( + (ChunkIndex) seekMap, + representationHolder.representation.presentationTimeOffsetUs)); } } } @@ -422,9 +438,14 @@ public class DefaultDashChunkSource implements DashChunkSource { return resolveTimeToLiveEdgePossible ? liveEdgeTimeUs - playbackPositionUs : C.TIME_UNSET; } - protected static Chunk newInitializationChunk(RepresentationHolder representationHolder, - DataSource dataSource, Format trackFormat, int trackSelectionReason, - Object trackSelectionData, RangedUri initializationUri, RangedUri indexUri) { + protected Chunk newInitializationChunk( + RepresentationHolder representationHolder, + DataSource dataSource, + Format trackFormat, + int trackSelectionReason, + Object trackSelectionData, + RangedUri initializationUri, + RangedUri indexUri) { RangedUri requestUri; String baseUrl = representationHolder.representation.baseUrl; if (initializationUri != null) { @@ -443,7 +464,7 @@ public class DefaultDashChunkSource implements DashChunkSource { trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper); } - protected static Chunk newMediaChunk( + protected Chunk newMediaChunk( RepresentationHolder representationHolder, DataSource dataSource, int trackType, @@ -497,18 +518,57 @@ public class DefaultDashChunkSource implements DashChunkSource { // Protected classes. - /** - * Holds information about a single {@link Representation}. - */ + /** {@link MediaChunkIterator} wrapping a {@link RepresentationHolder}. */ + protected static final class RepresentationSegmentIterator extends BaseMediaChunkIterator { + + private final RepresentationHolder representationHolder; + + /** + * Creates iterator. + * + * @param representation The {@link RepresentationHolder} to wrap. + * @param segmentNum The number of the segment this iterator will be pointing to initially. + * @param lastAvailableSegmentNum The number of the last available segment. + */ + public RepresentationSegmentIterator( + RepresentationHolder representation, long segmentNum, long lastAvailableSegmentNum) { + super(/* fromIndex= */ segmentNum, /* toIndex= */ lastAvailableSegmentNum); + this.representationHolder = representation; + } + + @Override + public DataSpec getDataSpec() { + checkInBounds(); + Representation representation = representationHolder.representation; + RangedUri segmentUri = representationHolder.getSegmentUrl(getCurrentIndex()); + Uri resolvedUri = segmentUri.resolveUri(representation.baseUrl); + String cacheKey = representation.getCacheKey(); + return new DataSpec(resolvedUri, segmentUri.start, segmentUri.length, cacheKey); + } + + @Override + public long getChunkStartTimeUs() { + checkInBounds(); + return representationHolder.getSegmentStartTimeUs(getCurrentIndex()); + } + + @Override + public long getChunkEndTimeUs() { + checkInBounds(); + return representationHolder.getSegmentEndTimeUs(getCurrentIndex()); + } + } + + /** Holds information about a snapshot of a single {@link Representation}. */ protected static final class RepresentationHolder { - /* package */ final ChunkExtractorWrapper extractorWrapper; + /* package */ final @Nullable ChunkExtractorWrapper extractorWrapper; - public Representation representation; - public DashSegmentIndex segmentIndex; + public final Representation representation; + public final @Nullable DashSegmentIndex segmentIndex; - private long periodDurationUs; - private long segmentNumShift; + private final long periodDurationUs; + private final long segmentNumShift; /* package */ RepresentationHolder( long periodDurationUs, @@ -517,80 +577,86 @@ public class DefaultDashChunkSource implements DashChunkSource { boolean enableEventMessageTrack, boolean enableCea608Track, TrackOutput playerEmsgTrackOutput) { - this.periodDurationUs = periodDurationUs; - this.representation = representation; - String containerMimeType = representation.format.containerMimeType; - if (mimeTypeIsRawText(containerMimeType)) { - extractorWrapper = null; - } else { - Extractor extractor; - if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { - extractor = new RawCcExtractor(representation.format); - } else if (mimeTypeIsWebm(containerMimeType)) { - extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES); - } else { - int flags = 0; - if (enableEventMessageTrack) { - flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK; - } - // TODO: Use caption format information from the manifest if available. - List closedCaptionFormats = enableCea608Track - ? Collections.singletonList( - Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null)) - : Collections.emptyList(); - - extractor = - new FragmentedMp4Extractor( - flags, null, null, null, closedCaptionFormats, playerEmsgTrackOutput); - } - // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, - // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. - extractorWrapper = new ChunkExtractorWrapper(extractor, trackType, representation.format); - } - segmentIndex = representation.getIndex(); + this( + periodDurationUs, + representation, + createExtractorWrapper( + trackType, + representation, + enableEventMessageTrack, + enableCea608Track, + playerEmsgTrackOutput), + /* segmentNumShift= */ 0, + representation.getIndex()); } - /* package */ void updateRepresentation(long newPeriodDurationUs, - Representation newRepresentation) throws BehindLiveWindowException { + private RepresentationHolder( + long periodDurationUs, + Representation representation, + @Nullable ChunkExtractorWrapper extractorWrapper, + long segmentNumShift, + @Nullable DashSegmentIndex segmentIndex) { + this.periodDurationUs = periodDurationUs; + this.representation = representation; + this.segmentNumShift = segmentNumShift; + this.extractorWrapper = extractorWrapper; + this.segmentIndex = segmentIndex; + } + + @CheckResult + /* package */ RepresentationHolder copyWithNewRepresentation( + long newPeriodDurationUs, Representation newRepresentation) + throws BehindLiveWindowException { DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex newIndex = newRepresentation.getIndex(); - periodDurationUs = newPeriodDurationUs; - representation = newRepresentation; if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. - return; + return new RepresentationHolder( + newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, oldIndex); } - segmentIndex = newIndex; if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. - return; + return new RepresentationHolder( + newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex); } - int oldIndexSegmentCount = oldIndex.getSegmentCount(periodDurationUs); + int oldIndexSegmentCount = oldIndex.getSegmentCount(newPeriodDurationUs); if (oldIndexSegmentCount == 0) { // Segment numbers cannot shift if the old index was empty. - return; + return new RepresentationHolder( + newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex); } long oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1; - long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) - + oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs); + long oldIndexEndTimeUs = + oldIndex.getTimeUs(oldIndexLastSegmentNum) + + oldIndex.getDurationUs(oldIndexLastSegmentNum, newPeriodDurationUs); long newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); + long newSegmentNumShift = segmentNumShift; if (oldIndexEndTimeUs == newIndexStartTimeUs) { // The new index continues where the old one ended, with no overlap. - segmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum; + newSegmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum; } else if (oldIndexEndTimeUs < newIndexStartTimeUs) { // There's a gap between the old index and the new one which means we've slipped behind the // live window and can't proceed. throw new BehindLiveWindowException(); } else { // The new index overlaps with the old one. - segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs) - - newIndexFirstSegmentNum; + newSegmentNumShift += + oldIndex.getSegmentNum(newIndexStartTimeUs, newPeriodDurationUs) + - newIndexFirstSegmentNum; } + return new RepresentationHolder( + newPeriodDurationUs, newRepresentation, extractorWrapper, newSegmentNumShift, newIndex); + } + + @CheckResult + /* package */ RepresentationHolder copyWithNewSegmentIndex(DashSegmentIndex segmentIndex) { + return new RepresentationHolder( + periodDurationUs, representation, extractorWrapper, segmentNumShift, segmentIndex); } public long getFirstSegmentNum() { @@ -626,5 +692,40 @@ public class DefaultDashChunkSource implements DashChunkSource { private static boolean mimeTypeIsRawText(String mimeType) { return MimeTypes.isText(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType); } + + private static @Nullable ChunkExtractorWrapper createExtractorWrapper( + int trackType, + Representation representation, + boolean enableEventMessageTrack, + boolean enableCea608Track, + TrackOutput playerEmsgTrackOutput) { + String containerMimeType = representation.format.containerMimeType; + if (mimeTypeIsRawText(containerMimeType)) { + return null; + } + Extractor extractor; + if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { + extractor = new RawCcExtractor(representation.format); + } else if (mimeTypeIsWebm(containerMimeType)) { + extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES); + } else { + int flags = 0; + if (enableEventMessageTrack) { + flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK; + } + // TODO: Use caption format information from the manifest if available. + List closedCaptionFormats = + enableCea608Track + ? Collections.singletonList( + Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null)) + : Collections.emptyList(); + extractor = + new FragmentedMp4Extractor( + flags, null, null, null, closedCaptionFormats, playerEmsgTrackOutput); + } + // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, + // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. + return new ChunkExtractorWrapper(extractor, trackType, representation.format); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/EventSampleStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/EventSampleStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java index 7b05f57ff..7fef59f6a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/EventSampleStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessage; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessageEncoder; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.dash.manifest.EventStream; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.metadata.emsg.EventMessage; +import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.dash.manifest.EventStream; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/PlayerEmsgHandler.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/PlayerEmsgHandler.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java index 58c43ba3f..a4a37cd90 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/PlayerEmsgHandler.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java @@ -13,28 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash; +package com.google.android.exoplayer2.source.dash; -import static org.telegram.messenger.exoplayer2.util.Util.parseXsDateTime; +import static com.google.android.exoplayer2.util.Util.parseXsDateTime; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.MetadataInputBuffer; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessage; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessageDecoder; -import org.telegram.messenger.exoplayer2.source.SampleQueue; -import org.telegram.messenger.exoplayer2.source.chunk.Chunk; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.MetadataInputBuffer; +import com.google.android.exoplayer2.metadata.emsg.EventMessage; +import com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.Iterator; import java.util.Map; @@ -100,7 +101,6 @@ public final class PlayerEmsgHandler implements Handler.Callback { * messages that generate DASH media source events. * @param allocator An {@link Allocator} from which allocations can be obtained. */ - @SuppressWarnings("nullness") public PlayerEmsgHandler( DashManifest manifest, PlayerEmsgCallback playerEmsgCallback, Allocator allocator) { this.manifest = manifest; @@ -108,7 +108,7 @@ public final class PlayerEmsgHandler implements Handler.Callback { this.allocator = allocator; manifestPublishTimeToExpiryTimeUs = new TreeMap<>(); - handler = new Handler(this); + handler = Util.createHandler(/* callback= */ this); decoder = new EventMessageDecoder(); lastLoadedChunkEndTimeUs = C.TIME_UNSET; lastLoadedChunkEndTimeBeforeRefreshUs = C.TIME_UNSET; @@ -336,7 +336,7 @@ public final class PlayerEmsgHandler implements Handler.Callback { @Override public void sampleMetadata( - long timeUs, int flags, int size, int offset, CryptoData encryptionData) { + long timeUs, int flags, int size, int offset, @Nullable CryptoData encryptionData) { sampleQueue.sampleMetadata(timeUs, flags, size, offset, encryptionData); parseAndDiscardSamples(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/AdaptationSet.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/AdaptationSet.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java index 556e37a59..d96237474 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/AdaptationSet.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import java.util.Collections; import java.util.List; @@ -35,7 +35,7 @@ public class AdaptationSet { public final int id; /** - * The type of the adaptation set. One of the {@link org.telegram.messenger.exoplayer2.C} + * The type of the adaptation set. One of the {@link com.google.android.exoplayer2.C} * {@code TRACK_TYPE_*} constants. */ public final int type; @@ -58,7 +58,7 @@ public class AdaptationSet { /** * @param id A non-negative identifier for the adaptation set that's unique in the scope of its * containing period, or {@link #ID_UNSET} if not specified. - * @param type The type of the adaptation set. One of the {@link org.telegram.messenger.exoplayer2.C} + * @param type The type of the adaptation set. One of the {@link com.google.android.exoplayer2.C} * {@code TRACK_TYPE_*} constants. * @param representations {@link Representation}s in the adaptation set. * @param accessibilityDescriptors Accessibility descriptors in the adaptation set. @@ -69,12 +69,14 @@ public class AdaptationSet { this.id = id; this.type = type; this.representations = Collections.unmodifiableList(representations); - this.accessibilityDescriptors = accessibilityDescriptors == null - ? Collections.emptyList() - : Collections.unmodifiableList(accessibilityDescriptors); - this.supplementalProperties = supplementalProperties == null - ? Collections.emptyList() - : Collections.unmodifiableList(supplementalProperties); + this.accessibilityDescriptors = + accessibilityDescriptors == null + ? Collections.emptyList() + : Collections.unmodifiableList(accessibilityDescriptors); + this.supplementalProperties = + supplementalProperties == null + ? Collections.emptyList() + : Collections.unmodifiableList(supplementalProperties); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifest.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifest.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java index 2305229e7..1fdb137be 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifest.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.offline.FilterableManifest; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.offline.FilterableManifest; +import com.google.android.exoplayer2.offline.StreamKey; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -27,7 +28,7 @@ import java.util.List; * Represents a DASH media presentation description (mpd), as defined by ISO/IEC 23009-1:2014 * Section 5.3.1.2. */ -public class DashManifest implements FilterableManifest { +public class DashManifest implements FilterableManifest { /** * The {@code availabilityStartTime} value in milliseconds since epoch, or {@link C#TIME_UNSET} if @@ -101,7 +102,7 @@ public class DashManifest implements FilterableManifestemptyList() : periods; + this.periods = periods == null ? Collections.emptyList() : periods; } public final int getPeriodCount() { @@ -123,10 +124,10 @@ public class DashManifest implements FilterableManifest streamKeys) { - LinkedList keys = new LinkedList<>(streamKeys); + public final DashManifest copy(List streamKeys) { + LinkedList keys = new LinkedList<>(streamKeys); Collections.sort(keys); - keys.add(new RepresentationKey(-1, -1, -1)); // Add a stopper key to the end + keys.add(new StreamKey(-1, -1, -1)); // Add a stopper key to the end ArrayList copyPeriods = new ArrayList<>(); long shiftMs = 0; @@ -153,21 +154,21 @@ public class DashManifest implements FilterableManifest copyAdaptationSets( - List adaptationSets, LinkedList keys) { - RepresentationKey key = keys.poll(); + List adaptationSets, LinkedList keys) { + StreamKey key = keys.poll(); int periodIndex = key.periodIndex; ArrayList copyAdaptationSets = new ArrayList<>(); do { - int adaptationSetIndex = key.adaptationSetIndex; + int adaptationSetIndex = key.groupIndex; AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex); List representations = adaptationSet.representations; ArrayList copyRepresentations = new ArrayList<>(); do { - Representation representation = representations.get(key.representationIndex); + Representation representation = representations.get(key.trackIndex); copyRepresentations.add(representation); key = keys.poll(); - } while(key.periodIndex == periodIndex && key.adaptationSetIndex == adaptationSetIndex); + } while (key.periodIndex == periodIndex && key.groupIndex == adaptationSetIndex); copyAdaptationSets.add(new AdaptationSet(adaptationSet.id, adaptationSet.type, copyRepresentations, adaptationSet.accessibilityDescriptors, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifestParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifestParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index f5e29ed13..a6754ba15 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; import android.text.TextUtils; @@ -21,23 +21,23 @@ import android.util.Base64; import android.util.Log; import android.util.Pair; import android.util.Xml; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.extractor.mp4.PsshAtomUtil; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessage; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.SegmentList; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.SegmentTemplate; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.SegmentTimelineElement; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.UriUtil; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.util.XmlPullParserUtil; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil; +import com.google.android.exoplayer2.metadata.emsg.EventMessage; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SegmentList; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SegmentTemplate; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SegmentTimelineElement; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.XmlPullParserUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -247,6 +247,7 @@ public class DashManifestParser extends DefaultHandler int audioChannels = Format.NO_VALUE; int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE); String language = xpp.getAttributeValue(null, "lang"); + String label = xpp.getAttributeValue(null, "label"); String drmSchemeType = null; ArrayList drmSchemeDatas = new ArrayList<>(); ArrayList inbandEventStreams = new ArrayList<>(); @@ -283,9 +284,22 @@ public class DashManifestParser extends DefaultHandler } else if (XmlPullParserUtil.isStartTag(xpp, "SupplementalProperty")) { supplementalProperties.add(parseDescriptor(xpp, "SupplementalProperty")); } else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) { - RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs, - width, height, frameRate, audioChannels, audioSamplingRate, language, - selectionFlags, accessibilityDescriptors, segmentBase); + RepresentationInfo representationInfo = + parseRepresentation( + xpp, + baseUrl, + label, + mimeType, + codecs, + width, + height, + frameRate, + audioChannels, + audioSamplingRate, + language, + selectionFlags, + accessibilityDescriptors, + segmentBase); contentType = checkContentTypeConsistency(contentType, getContentType(representationInfo.format)); representationInfos.add(representationInfo); @@ -355,6 +369,7 @@ public class DashManifestParser extends DefaultHandler protected Pair parseContentProtection(XmlPullParser xpp) throws XmlPullParserException, IOException { String schemeType = null; + String licenseServerUrl = null; byte[] data = null; UUID uuid = null; boolean requiresSecureDecoder = false; @@ -389,7 +404,9 @@ public class DashManifestParser extends DefaultHandler do { xpp.next(); - if (XmlPullParserUtil.isStartTag(xpp, "widevine:license")) { + if (XmlPullParserUtil.isStartTag(xpp, "ms:laurl")) { + licenseServerUrl = xpp.getAttributeValue(null, "licenseUrl"); + } else if (XmlPullParserUtil.isStartTag(xpp, "widevine:license")) { String robustnessLevel = xpp.getAttributeValue(null, "robustness_level"); requiresSecureDecoder = robustnessLevel != null && robustnessLevel.startsWith("HW"); } else if (data == null) { @@ -409,8 +426,11 @@ public class DashManifestParser extends DefaultHandler } } } while (!XmlPullParserUtil.isEndTag(xpp, "ContentProtection")); - SchemeData schemeData = uuid != null - ? new SchemeData(uuid, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder) : null; + SchemeData schemeData = + uuid != null + ? new SchemeData( + uuid, licenseServerUrl, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder) + : null; return Pair.create(schemeType, schemeData); } @@ -446,12 +466,21 @@ public class DashManifestParser extends DefaultHandler // Representation parsing. - protected RepresentationInfo parseRepresentation(XmlPullParser xpp, String baseUrl, - String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth, - int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, - int adaptationSetAudioSamplingRate, String adaptationSetLanguage, + protected RepresentationInfo parseRepresentation( + XmlPullParser xpp, + String baseUrl, + String label, + String adaptationSetMimeType, + String adaptationSetCodecs, + int adaptationSetWidth, + int adaptationSetHeight, + float adaptationSetFrameRate, + int adaptationSetAudioChannels, + int adaptationSetAudioSamplingRate, + String adaptationSetLanguage, @C.SelectionFlags int adaptationSetSelectionFlags, - List adaptationSetAccessibilityDescriptors, SegmentBase segmentBase) + List adaptationSetAccessibilityDescriptors, + SegmentBase segmentBase) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); @@ -499,30 +528,74 @@ public class DashManifestParser extends DefaultHandler } } while (!XmlPullParserUtil.isEndTag(xpp, "Representation")); - Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels, - audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetSelectionFlags, - adaptationSetAccessibilityDescriptors, codecs, supplementalProperties); + Format format = + buildFormat( + id, + label, + mimeType, + width, + height, + frameRate, + audioChannels, + audioSamplingRate, + bandwidth, + adaptationSetLanguage, + adaptationSetSelectionFlags, + adaptationSetAccessibilityDescriptors, + codecs, + supplementalProperties); segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(); return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeType, drmSchemeDatas, inbandEventStreams, Representation.REVISION_ID_DEFAULT); } - protected Format buildFormat(String id, String containerMimeType, int width, int height, - float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language, - @C.SelectionFlags int selectionFlags, List accessibilityDescriptors, - String codecs, List supplementalProperties) { + protected Format buildFormat( + String id, + String label, + String containerMimeType, + int width, + int height, + float frameRate, + int audioChannels, + int audioSamplingRate, + int bitrate, + String language, + @C.SelectionFlags int selectionFlags, + List accessibilityDescriptors, + String codecs, + List supplementalProperties) { String sampleMimeType = getSampleMimeType(containerMimeType, codecs); if (sampleMimeType != null) { if (MimeTypes.AUDIO_E_AC3.equals(sampleMimeType)) { sampleMimeType = parseEac3SupplementalProperties(supplementalProperties); } if (MimeTypes.isVideo(sampleMimeType)) { - return Format.createVideoContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, width, height, frameRate, null, selectionFlags); + return Format.createVideoContainerFormat( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + width, + height, + frameRate, + /* initializationData= */ null, + selectionFlags); } else if (MimeTypes.isAudio(sampleMimeType)) { - return Format.createAudioContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, audioChannels, audioSamplingRate, null, selectionFlags, language); + return Format.createAudioContainerFormat( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + audioChannels, + audioSamplingRate, + /* initializationData= */ null, + selectionFlags, + language); } else if (mimeTypeIsRawText(sampleMimeType)) { int accessibilityChannel; if (MimeTypes.APPLICATION_CEA608.equals(sampleMimeType)) { @@ -532,12 +605,20 @@ public class DashManifestParser extends DefaultHandler } else { accessibilityChannel = Format.NO_VALUE; } - return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, selectionFlags, language, accessibilityChannel); + return Format.createTextContainerFormat( + id, + label, + containerMimeType, + sampleMimeType, + codecs, + bitrate, + selectionFlags, + language, + accessibilityChannel); } } - return Format.createContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate, - selectionFlags, language); + return Format.createContainerFormat( + id, label, containerMimeType, sampleMimeType, codecs, bitrate, selectionFlags, language); } protected Representation buildRepresentation(RepresentationInfo representationInfo, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Descriptor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Descriptor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java index a813c57c5..0e21df64b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Descriptor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** * A descriptor, as defined by ISO 23009-1, 2nd edition, 5.8.2. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/EventStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/EventStream.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/EventStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/EventStream.java index 8f631c3bb..8a4e1ad05 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/EventStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/EventStream.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; -import org.telegram.messenger.exoplayer2.metadata.emsg.EventMessage; +import com.google.android.exoplayer2.metadata.emsg.EventMessage; /** * A DASH in-MPD EventStream element, as defined by ISO/IEC 23009-1, 2nd edition, section 5.10. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Period.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Period.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Period.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Period.java index 32dd61505..b6f7ef0a3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Period.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Period.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.util.Collections; import java.util.List; @@ -51,7 +51,7 @@ public class Period { * @param adaptationSets The adaptation sets belonging to the period. */ public Period(@Nullable String id, long startMs, List adaptationSets) { - this(id, startMs, adaptationSets, Collections.emptyList()); + this(id, startMs, adaptationSets, Collections.emptyList()); } /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RangedUri.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RangedUri.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java index 5356465b3..e22666733 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RangedUri.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.UriUtil; /** * Defines a range of data located at a reference uri. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Representation.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Representation.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java index 8db379a1f..44daa1d01 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/Representation.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.source.dash.DashSegmentIndex; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.MultiSegmentBase; -import org.telegram.messenger.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.dash.DashSegmentIndex; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.MultiSegmentBase; +import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase; import java.util.Collections; import java.util.List; @@ -135,8 +135,10 @@ public abstract class Representation { this.revisionId = revisionId; this.format = format; this.baseUrl = baseUrl; - this.inbandEventStreams = inbandEventStreams == null ? Collections.emptyList() - : Collections.unmodifiableList(inbandEventStreams); + this.inbandEventStreams = + inbandEventStreams == null + ? Collections.emptyList() + : Collections.unmodifiableList(inbandEventStreams); initializationUri = segmentBase.getInitialization(this); presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SegmentBase.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SegmentBase.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java index 0e503f998..f03323259 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SegmentBase.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.source.dash.DashSegmentIndex; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.source.dash.DashSegmentIndex; +import com.google.android.exoplayer2.util.Util; import java.util.List; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SingleSegmentIndex.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SingleSegmentIndex.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SingleSegmentIndex.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SingleSegmentIndex.java index c9b8fd809..a56a11fe5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/SingleSegmentIndex.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SingleSegmentIndex.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; -import org.telegram.messenger.exoplayer2.source.dash.DashSegmentIndex; +import com.google.android.exoplayer2.source.dash.DashSegmentIndex; /** * A {@link DashSegmentIndex} that defines a single segment. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UrlTemplate.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UrlTemplate.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UrlTemplate.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UrlTemplate.java index c73622317..a7ce7eb9a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UrlTemplate.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UrlTemplate.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; import java.util.Locale; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UtcTimingElement.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UtcTimingElement.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UtcTimingElement.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UtcTimingElement.java index cc216c038..79e745245 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/UtcTimingElement.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/manifest/UtcTimingElement.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; +package com.google.android.exoplayer2.source.dash.manifest; /** * Represents a UTCTiming element. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java similarity index 51% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadAction.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java index f6ad792eb..f36a018e5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadAction.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java @@ -13,62 +13,72 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.offline; +package com.google.android.exoplayer2.source.dash.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.offline.DownloadAction; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloadAction; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RepresentationKey; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import com.google.android.exoplayer2.offline.DownloadAction; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloadAction; +import com.google.android.exoplayer2.offline.StreamKey; +import java.util.Collections; import java.util.List; /** An action to download or remove downloaded DASH streams. */ -public final class DashDownloadAction extends SegmentDownloadAction { +public final class DashDownloadAction extends SegmentDownloadAction { private static final String TYPE = "dash"; private static final int VERSION = 0; public static final Deserializer DESERIALIZER = - new SegmentDownloadActionDeserializer(TYPE, VERSION) { - - @Override - protected RepresentationKey readKey(DataInputStream input) throws IOException { - return new RepresentationKey(input.readInt(), input.readInt(), input.readInt()); - } - + new SegmentDownloadActionDeserializer(TYPE, VERSION) { @Override protected DownloadAction createDownloadAction( - Uri uri, boolean isRemoveAction, byte[] data, List keys) { + Uri uri, boolean isRemoveAction, byte[] data, List keys) { return new DashDownloadAction(uri, isRemoveAction, data, keys); } }; + /** + * Creates a DASH download action. + * + * @param uri The URI of the media to be downloaded. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + * @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded. + */ + public static DashDownloadAction createDownloadAction( + Uri uri, @Nullable byte[] data, List keys) { + return new DashDownloadAction(uri, /* isRemoveAction= */ false, data, keys); + } + + /** + * Creates a DASH remove action. + * + * @param uri The URI of the media to be removed. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + */ + public static DashDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) { + return new DashDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + } + /** * @param uri The DASH manifest URI. * @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded. * @param data Optional custom data for this action. * @param keys Keys of representations to be downloaded. If empty, all representations are * downloaded. If {@code removeAction} is true, {@code keys} must be empty. + * @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link + * #createRemoveAction(Uri, byte[])}. */ + @Deprecated public DashDownloadAction( - Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { + Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { super(TYPE, VERSION, uri, isRemoveAction, data, keys); } @Override - protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { + public DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { return new DashDownloader(uri, keys, constructorHelper); } - @Override - protected void writeKey(DataOutputStream output, RepresentationKey key) throws IOException { - output.writeInt(key.periodIndex); - output.writeInt(key.adaptationSetIndex); - output.writeInt(key.representationIndex); - } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadHelper.java similarity index 60% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadHelper.java index 2772ccdcd..91e41b9de 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloadHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadHelper.java @@ -13,27 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.offline; +package com.google.android.exoplayer2.source.dash.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.offline.DownloadHelper; -import org.telegram.messenger.exoplayer2.offline.TrackKey; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.dash.manifest.AdaptationSet; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifestParser; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Representation; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RepresentationKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.offline.DownloadHelper; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.offline.TrackKey; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; +import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** A {@link DownloadHelper} for DASH streams. */ public final class DashDownloadHelper extends DownloadHelper { @@ -41,7 +42,7 @@ public final class DashDownloadHelper extends DownloadHelper { private final Uri uri; private final DataSource.Factory manifestDataSourceFactory; - private DashManifest manifest; + private @MonotonicNonNull DashManifest manifest; public DashDownloadHelper(Uri uri, DataSource.Factory manifestDataSourceFactory) { this.uri = uri; @@ -50,9 +51,9 @@ public final class DashDownloadHelper extends DownloadHelper { @Override protected void prepareInternal() throws IOException { + DataSource dataSource = manifestDataSourceFactory.createDataSource(); manifest = - ParsingLoadable.load( - manifestDataSourceFactory.createDataSource(), new DashManifestParser(), uri); + ParsingLoadable.load(dataSource, new DashManifestParser(), uri, C.DATA_TYPE_MANIFEST); } /** Returns the DASH manifest. Must not be called until after preparation completes. */ @@ -86,23 +87,20 @@ public final class DashDownloadHelper extends DownloadHelper { @Override public DashDownloadAction getDownloadAction(@Nullable byte[] data, List trackKeys) { - return new DashDownloadAction( - uri, /* isRemoveAction= */ false, data, toRepresentationKeys(trackKeys)); + return DashDownloadAction.createDownloadAction(uri, data, toStreamKeys(trackKeys)); } @Override public DashDownloadAction getRemoveAction(@Nullable byte[] data) { - return new DashDownloadAction( - uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + return DashDownloadAction.createRemoveAction(uri, data); } - private static List toRepresentationKeys(List trackKeys) { - List representationKeys = new ArrayList<>(trackKeys.size()); + private static List toStreamKeys(List trackKeys) { + List streamKeys = new ArrayList<>(trackKeys.size()); for (int i = 0; i < trackKeys.size(); i++) { TrackKey trackKey = trackKeys.get(i); - representationKeys.add( - new RepresentationKey(trackKey.periodIndex, trackKey.groupIndex, trackKey.trackIndex)); + streamKeys.add(new StreamKey(trackKey.periodIndex, trackKey.groupIndex, trackKey.trackIndex)); } - return representationKeys; + return streamKeys; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java index 504376f95..68120d617 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/offline/DashDownloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java @@ -13,26 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.dash.offline; +package com.google.android.exoplayer2.source.dash.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; -import org.telegram.messenger.exoplayer2.offline.DownloadException; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloader; -import org.telegram.messenger.exoplayer2.source.dash.DashSegmentIndex; -import org.telegram.messenger.exoplayer2.source.dash.DashUtil; -import org.telegram.messenger.exoplayer2.source.dash.DashWrappingSegmentIndex; -import org.telegram.messenger.exoplayer2.source.dash.manifest.AdaptationSet; -import org.telegram.messenger.exoplayer2.source.dash.manifest.DashManifest; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Period; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RangedUri; -import org.telegram.messenger.exoplayer2.source.dash.manifest.Representation; -import org.telegram.messenger.exoplayer2.source.dash.manifest.RepresentationKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.offline.DownloadException; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloader; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.source.dash.DashSegmentIndex; +import com.google.android.exoplayer2.source.dash.DashUtil; +import com.google.android.exoplayer2.source.dash.DashWrappingSegmentIndex; +import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; +import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.Period; +import com.google.android.exoplayer2.source.dash.manifest.RangedUri; +import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -51,9 +51,7 @@ import java.util.List; * // period. * DashDownloader dashDownloader = * new DashDownloader( - * manifestUrl, - * Collections.singletonList(new RepresentationKey(0, 0, 0)), - * constructorHelper); + * manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), constructorHelper); * // Perform the download. * dashDownloader.download(); * // Access downloaded data using CacheDataSource @@ -61,19 +59,17 @@ import java.util.List; * new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE); * } */ -public final class DashDownloader extends SegmentDownloader { +public final class DashDownloader extends SegmentDownloader { /** * @param manifestUri The {@link Uri} of the manifest to be downloaded. - * @param representationKeys Keys defining which representations in the manifest should be - * selected for download. If empty, all representations are downloaded. + * @param streamKeys Keys defining which representations in the manifest should be selected for + * download. If empty, all representations are downloaded. * @param constructorHelper A {@link DownloaderConstructorHelper} instance. */ public DashDownloader( - Uri manifestUri, - List representationKeys, - DownloaderConstructorHelper constructorHelper) { - super(manifestUri, representationKeys, constructorHelper); + Uri manifestUri, List streamKeys, DownloaderConstructorHelper constructorHelper) { + super(manifestUri, streamKeys, constructorHelper); } @Override @@ -167,7 +163,9 @@ public final class DashDownloader extends SegmentDownloader> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + + @Override + public void close() throws IOException { + if (cipherInputStream != null) { + cipherInputStream = null; + upstream.close(); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java index 5441e97ce..b90dcb213 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsDataSourceFactory.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; -import org.telegram.messenger.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSource; /** * Default implementation of {@link HlsDataSourceFactory}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsExtractorFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java similarity index 70% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsExtractorFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java index 3d13b4136..35c71fc86 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/DefaultHlsExtractorFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java @@ -13,24 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.net.Uri; import android.text.TextUtils; import android.util.Pair; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.mp3.Mp3Extractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import org.telegram.messenger.exoplayer2.extractor.ts.Ac3Extractor; -import org.telegram.messenger.exoplayer2.extractor.ts.AdtsExtractor; -import org.telegram.messenger.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; -import org.telegram.messenger.exoplayer2.extractor.ts.TsExtractor; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; +import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; +import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; +import com.google.android.exoplayer2.extractor.ts.TsExtractor; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.util.Collections; import java.util.List; +import java.util.Map; /** * Default {@link HlsExtractorFactory} implementation. @@ -48,9 +49,14 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { public static final String WEBVTT_FILE_EXTENSION = ".webvtt"; @Override - public Pair createExtractor(Extractor previousExtractor, Uri uri, - Format format, List muxedCaptionFormats, DrmInitData drmInitData, - TimestampAdjuster timestampAdjuster) { + public Pair createExtractor( + Extractor previousExtractor, + Uri uri, + Format format, + List muxedCaptionFormats, + DrmInitData drmInitData, + TimestampAdjuster timestampAdjuster, + Map> responseHeaders) { String lastPathSegment = uri.getLastPathSegment(); if (lastPathSegment == null) { lastPathSegment = ""; @@ -77,8 +83,13 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { } else if (lastPathSegment.endsWith(MP4_FILE_EXTENSION) || lastPathSegment.startsWith(M4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 4) || lastPathSegment.startsWith(MP4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)) { - extractor = new FragmentedMp4Extractor(0, timestampAdjuster, null, drmInitData, - muxedCaptionFormats != null ? muxedCaptionFormats : Collections.emptyList()); + extractor = + new FragmentedMp4Extractor( + /* flags= */ 0, + timestampAdjuster, + /* sideloadedTrack= */ null, + drmInitData, + muxedCaptionFormats != null ? muxedCaptionFormats : Collections.emptyList()); } else { // For any other file extension, we assume TS format. @DefaultTsPayloadReaderFactory.Flags @@ -87,7 +98,15 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { // The playlist declares closed caption renditions, we should ignore descriptors. esReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS; } else { - muxedCaptionFormats = Collections.emptyList(); + // The playlist does not provide any closed caption information. We preemptively declare a + // closed caption track on channel 0. + muxedCaptionFormats = + Collections.singletonList( + Format.createTextSampleFormat( + /* id= */ null, + MimeTypes.APPLICATION_CEA608, + /* selectionFlags= */ 0, + /* language= */ null)); } String codecs = format.codecs; if (!TextUtils.isEmpty(codecs)) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index f91f86c07..f82432d60 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -13,28 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.net.Uri; import android.os.SystemClock; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.source.BehindLiveWindowException; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.chunk.Chunk; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; -import org.telegram.messenger.exoplayer2.source.chunk.DataChunk; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistTracker; -import org.telegram.messenger.exoplayer2.trackselection.BaseTrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; -import org.telegram.messenger.exoplayer2.util.UriUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.BehindLiveWindowException; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; +import com.google.android.exoplayer2.source.chunk.DataChunk; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; +import com.google.android.exoplayer2.trackselection.BaseTrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.math.BigInteger; import java.util.Arrays; @@ -104,7 +106,7 @@ import java.util.List; // the way in which HlsSampleStreamWrapper generates track groups. Use only index based methods // in TrackSelection to avoid unexpected behavior. private TrackSelection trackSelection; - private long liveEdgeTimeUs; + private long liveEdgeInPeriodTimeUs; private boolean seenExpectedPlaylistError; /** @@ -114,21 +116,28 @@ import java.util.List; * @param variants The available variants. * @param dataSourceFactory An {@link HlsDataSourceFactory} to create {@link DataSource}s for the * chunks. - * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If - * multiple {@link HlsChunkSource}s are used for a single playback, they should all share the - * same provider. + * @param mediaTransferListener The transfer listener which should be informed of any media data + * transfers. May be null if no listener is available. + * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If multiple + * {@link HlsChunkSource}s are used for a single playback, they should all share the same + * provider. * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption * information is available in the master playlist. */ - public HlsChunkSource(HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker, - HlsUrl[] variants, HlsDataSourceFactory dataSourceFactory, - TimestampAdjusterProvider timestampAdjusterProvider, List muxedCaptionFormats) { + public HlsChunkSource( + HlsExtractorFactory extractorFactory, + HlsPlaylistTracker playlistTracker, + HlsUrl[] variants, + HlsDataSourceFactory dataSourceFactory, + @Nullable TransferListener mediaTransferListener, + TimestampAdjusterProvider timestampAdjusterProvider, + List muxedCaptionFormats) { this.extractorFactory = extractorFactory; this.playlistTracker = playlistTracker; this.variants = variants; this.timestampAdjusterProvider = timestampAdjusterProvider; this.muxedCaptionFormats = muxedCaptionFormats; - liveEdgeTimeUs = C.TIME_UNSET; + liveEdgeInPeriodTimeUs = C.TIME_UNSET; Format[] variantFormats = new Format[variants.length]; int[] initialTrackSelection = new int[variants.length]; for (int i = 0; i < variants.length; i++) { @@ -136,6 +145,9 @@ import java.util.List; initialTrackSelection[i] = i; } mediaDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_MEDIA); + if (mediaTransferListener != null) { + mediaDataSource.addTransferListener(mediaTransferListener); + } encryptionDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_DRM); trackGroup = new TrackGroup(variantFormats); trackSelection = new InitializationTrackSelection(trackGroup, initialTrackSelection); @@ -204,18 +216,20 @@ import java.util.List; * but the end of the stream has not been reached, {@link HlsChunkHolder#playlist} is set to * contain the {@link HlsUrl} that refers to the playlist that needs refreshing. * - * @param previous The most recently loaded media chunk. * @param playbackPositionUs The current playback position relative to the period start in * microseconds. If playback of the period to which this chunk source belongs has not yet * started, the value will be the starting position in the period minus the duration of any * media in previous periods still to be played. * @param loadPositionUs The current load position relative to the period start in microseconds. - * If {@code previous} is null, this is the starting position from which chunks should be - * provided. Else it's equal to {@code previous.endTimeUs}. + * If {@code queue} is empty, this is the starting position from which chunks should be + * provided. Else it's equal to {@link HlsMediaChunk#endTimeUs} of the last chunk in the + * {@code queue}. + * @param queue The queue of buffered {@link HlsMediaChunk}s. * @param out A holder to populate. */ public void getNextChunk( - HlsMediaChunk previous, long playbackPositionUs, long loadPositionUs, HlsChunkHolder out) { + long playbackPositionUs, long loadPositionUs, List queue, HlsChunkHolder out) { + HlsMediaChunk previous = queue.isEmpty() ? null : queue.get(queue.size() - 1); int oldVariantIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat); long bufferedDurationUs = loadPositionUs - playbackPositionUs; @@ -248,22 +262,23 @@ import java.util.List; return; } HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl); - independentSegments = mediaPlaylist.hasIndependentSegmentsTag; + independentSegments = mediaPlaylist.hasIndependentSegments; updateLiveEdgeTimeUs(mediaPlaylist); // Select the chunk. long chunkMediaSequence; + long startOfPlaylistInPeriodUs = + mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); if (previous == null || switchingVariant) { - long targetPositionUs = (previous == null || independentSegments) ? loadPositionUs - : previous.startTimeUs; - if (!mediaPlaylist.hasEndTag && targetPositionUs >= mediaPlaylist.getEndTimeUs()) { + long endOfPlaylistInPeriodUs = startOfPlaylistInPeriodUs + mediaPlaylist.durationUs; + long targetPositionInPeriodUs = + (previous == null || independentSegments) ? loadPositionUs : previous.startTimeUs; + if (!mediaPlaylist.hasEndTag && targetPositionInPeriodUs >= endOfPlaylistInPeriodUs) { // If the playlist is too old to contain the chunk, we need to refresh it. chunkMediaSequence = mediaPlaylist.mediaSequence + mediaPlaylist.segments.size(); } else { - long positionOfPlaylistInPeriodUs = - mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); - long targetPositionInPlaylistUs = targetPositionUs - positionOfPlaylistInPeriodUs; + long targetPositionInPlaylistUs = targetPositionInPeriodUs - startOfPlaylistInPeriodUs; chunkMediaSequence = Util.binarySearchFloor( mediaPlaylist.segments, @@ -277,6 +292,8 @@ import java.util.List; selectedVariantIndex = oldVariantIndex; selectedUrl = variants[selectedVariantIndex]; mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl); + startOfPlaylistInPeriodUs = + mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); chunkMediaSequence = previous.getNextChunkIndex(); } } @@ -331,9 +348,7 @@ import java.util.List; } // Compute start time of the next chunk. - long positionOfPlaylistInPeriodUs = - mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); - long segmentStartTimeInPeriodUs = positionOfPlaylistInPeriodUs + segment.relativeStartTimeUs; + long segmentStartTimeInPeriodUs = startOfPlaylistInPeriodUs + segment.relativeStartTimeUs; int discontinuitySequence = mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence; TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster( @@ -382,17 +397,17 @@ import java.util.List; } /** - * Called when the {@link HlsSampleStreamWrapper} encounters an error loading a chunk obtained - * from this source. + * Attempts to blacklist the track associated with the given chunk. Blacklisting will fail if the + * track is the only non-blacklisted track in the selection. * - * @param chunk The chunk whose load encountered the error. - * @param cancelable Whether the load can be canceled. - * @param error The error. - * @return Whether the load should be canceled. + * @param chunk The chunk whose load caused the blacklisting attempt. + * @param blacklistDurationMs The number of milliseconds for which the track selection should be + * blacklisted. + * @return Whether the blacklisting succeeded. */ - public boolean onChunkLoadError(Chunk chunk, boolean cancelable, IOException error) { - return cancelable && ChunkedTrackBlacklistUtil.maybeBlacklistTrack(trackSelection, - trackSelection.indexOf(trackGroup.indexOf(chunk.trackFormat)), error); + public boolean maybeBlacklistTrack(Chunk chunk, long blacklistDurationMs) { + return trackSelection.blacklist( + trackSelection.indexOf(trackGroup.indexOf(chunk.trackFormat)), blacklistDurationMs); } /** @@ -420,12 +435,17 @@ import java.util.List; // Private methods. private long resolveTimeToLiveEdgeUs(long playbackPositionUs) { - final boolean resolveTimeToLiveEdgePossible = liveEdgeTimeUs != C.TIME_UNSET; - return resolveTimeToLiveEdgePossible ? liveEdgeTimeUs - playbackPositionUs : C.TIME_UNSET; + final boolean resolveTimeToLiveEdgePossible = liveEdgeInPeriodTimeUs != C.TIME_UNSET; + return resolveTimeToLiveEdgePossible + ? liveEdgeInPeriodTimeUs - playbackPositionUs + : C.TIME_UNSET; } private void updateLiveEdgeTimeUs(HlsMediaPlaylist mediaPlaylist) { - liveEdgeTimeUs = mediaPlaylist.hasEndTag ? C.TIME_UNSET : mediaPlaylist.getEndTimeUs(); + liveEdgeInPeriodTimeUs = + mediaPlaylist.hasEndTag + ? C.TIME_UNSET + : (mediaPlaylist.getEndTimeUs() - playlistTracker.getInitialStartTimeUs()); } private EncryptionKeyChunk newEncryptionKeyChunk(Uri keyUri, String iv, int variantIndex, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsDataSourceFactory.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsDataSourceFactory.java index 580003455..30e7af5a0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsDataSourceFactory.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; /** * Creates {@link DataSource}s for HLS playlists, encryption and media chunks. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsExtractorFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsExtractorFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java index e4a34d9a3..a75751815 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsExtractorFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.net.Uri; import android.util.Pair; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.util.List; +import java.util.Map; /** * Factory for HLS media chunk extractors. @@ -42,12 +43,18 @@ public interface HlsExtractorFactory { * information is available in the master playlist. * @param drmInitData {@link DrmInitData} associated with the chunk. * @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number. + * @param responseHeaders The HTTP response headers associated with the media segment or + * initialization section to extract. * @return A pair containing the {@link Extractor} and a boolean that indicates whether it is a * packed audio extractor. The first element may be {@code previousExtractor} if the factory * has determined it can be re-used. */ - Pair createExtractor(Extractor previousExtractor, Uri uri, Format format, - List muxedCaptionFormats, DrmInitData drmInitData, - TimestampAdjuster timestampAdjuster); - + Pair createExtractor( + Extractor previousExtractor, + Uri uri, + Format format, + List muxedCaptionFormats, + DrmInitData drmInitData, + TimestampAdjuster timestampAdjuster, + Map> responseHeaders); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsManifest.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsManifest.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsManifest.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsManifest.java index e19f3405f..81d63fd4a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsManifest.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsManifest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; /** * Holds a master playlist along with a snapshot of one of its media playlists. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaChunk.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaChunk.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 065ce405f..8c151e59c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaChunk.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -13,25 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.metadata.id3.Id3Decoder; -import org.telegram.messenger.exoplayer2.metadata.id3.PrivFrame; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.extractor.DefaultExtractorInput; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.id3.Id3Decoder; +import com.google.android.exoplayer2.metadata.id3.PrivFrame; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -69,19 +69,22 @@ import java.util.concurrent.atomic.AtomicInteger; private final boolean hasGapTag; private final TimestampAdjuster timestampAdjuster; private final boolean shouldSpliceIn; - private final Extractor extractor; - private final boolean isPackedAudioExtractor; - private final boolean reusingExtractor; - private final Id3Decoder id3Decoder; - private final ParsableByteArray id3Data; + private final HlsExtractorFactory extractorFactory; + private final List muxedCaptionFormats; + private final DrmInitData drmInitData; + private final Extractor previousExtractor; + private Extractor extractor; + private boolean isPackedAudioExtractor; + private Id3Decoder id3Decoder; + private ParsableByteArray id3Data; private HlsSampleStreamWrapper output; private int initSegmentBytesLoaded; - private int bytesLoaded; + private int nextLoadPosition; private boolean id3TimestampPeeked; private boolean initLoadCompleted; private volatile boolean loadCanceled; - private volatile boolean loadCompleted; + private boolean loadCompleted; /** * @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor @@ -142,35 +145,22 @@ import java.util.concurrent.atomic.AtomicInteger; this.hlsUrl = hlsUrl; this.isMasterTimestampSource = isMasterTimestampSource; this.timestampAdjuster = timestampAdjuster; - // Note: this.dataSource and dataSource may be different. - this.isEncrypted = this.dataSource instanceof Aes128DataSource; + this.isEncrypted = fullSegmentEncryptionKey != null; this.hasGapTag = hasGapTag; + this.extractorFactory = extractorFactory; + this.muxedCaptionFormats = muxedCaptionFormats; + this.drmInitData = drmInitData; Extractor previousExtractor = null; if (previousChunk != null) { + id3Decoder = previousChunk.id3Decoder; + id3Data = previousChunk.id3Data; shouldSpliceIn = previousChunk.hlsUrl != hlsUrl; previousExtractor = previousChunk.discontinuitySequenceNumber != discontinuitySequenceNumber || shouldSpliceIn ? null : previousChunk.extractor; } else { shouldSpliceIn = false; } - Pair extractorData = extractorFactory.createExtractor(previousExtractor, - dataSpec.uri, trackFormat, muxedCaptionFormats, drmInitData, timestampAdjuster); - extractor = extractorData.first; - isPackedAudioExtractor = extractorData.second; - reusingExtractor = extractor == previousExtractor; - initLoadCompleted = reusingExtractor && initDataSpec != null; - if (isPackedAudioExtractor) { - if (previousChunk != null && previousChunk.id3Data != null) { - id3Decoder = previousChunk.id3Decoder; - id3Data = previousChunk.id3Data; - } else { - id3Decoder = new Id3Decoder(); - id3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH); - } - } else { - id3Decoder = null; - id3Data = null; - } + this.previousExtractor = previousExtractor; initDataSource = dataSource; uid = uidSource.getAndIncrement(); } @@ -183,10 +173,6 @@ import java.util.concurrent.atomic.AtomicInteger; */ public void init(HlsSampleStreamWrapper output) { this.output = output; - output.init(uid, shouldSpliceIn, reusingExtractor); - if (!reusingExtractor) { - extractor.init(output); - } } @Override @@ -194,11 +180,6 @@ import java.util.concurrent.atomic.AtomicInteger; return loadCompleted; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation @Override @@ -206,11 +187,6 @@ import java.util.concurrent.atomic.AtomicInteger; loadCanceled = true; } - @Override - public boolean isLoadCanceled() { - return loadCanceled; - } - @Override public void load() throws IOException, InterruptedException { maybeLoadInitData(); @@ -222,7 +198,7 @@ import java.util.concurrent.atomic.AtomicInteger; } } - // Internal loading methods. + // Internal methods. private void maybeLoadInitData() throws IOException, InterruptedException { if (initLoadCompleted || initDataSpec == null) { @@ -231,8 +207,7 @@ import java.util.concurrent.atomic.AtomicInteger; } DataSpec initSegmentDataSpec = initDataSpec.subrange(initSegmentBytesLoaded); try { - ExtractorInput input = new DefaultExtractorInput(initDataSource, - initSegmentDataSpec.absoluteStreamPosition, initDataSource.open(initSegmentDataSpec)); + DefaultExtractorInput input = prepareExtraction(initDataSource, initSegmentDataSpec); try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { @@ -242,7 +217,7 @@ import java.util.concurrent.atomic.AtomicInteger; initSegmentBytesLoaded = (int) (input.getPosition() - initDataSpec.absoluteStreamPosition); } } finally { - Util.closeQuietly(dataSource); + Util.closeQuietly(initDataSource); } initLoadCompleted = true; } @@ -256,9 +231,9 @@ import java.util.concurrent.atomic.AtomicInteger; boolean skipLoadedBytes; if (isEncrypted) { loadDataSpec = dataSpec; - skipLoadedBytes = bytesLoaded != 0; + skipLoadedBytes = nextLoadPosition != 0; } else { - loadDataSpec = dataSpec.subrange(bytesLoaded); + loadDataSpec = dataSpec.subrange(nextLoadPosition); skipLoadedBytes = false; } if (!isMasterTimestampSource) { @@ -268,8 +243,7 @@ import java.util.concurrent.atomic.AtomicInteger; timestampAdjuster.setFirstSampleTimestampUs(startTimeUs); } try { - ExtractorInput input = new DefaultExtractorInput(dataSource, - loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); + ExtractorInput input = prepareExtraction(dataSource, loadDataSpec); if (isPackedAudioExtractor && !id3TimestampPeeked) { long id3Timestamp = peekId3PrivTimestamp(input); id3TimestampPeeked = true; @@ -277,7 +251,7 @@ import java.util.concurrent.atomic.AtomicInteger; ? timestampAdjuster.adjustTsTimestamp(id3Timestamp) : startTimeUs); } if (skipLoadedBytes) { - input.skipFully(bytesLoaded); + input.skipFully(nextLoadPosition); } try { int result = Extractor.RESULT_CONTINUE; @@ -285,13 +259,44 @@ import java.util.concurrent.atomic.AtomicInteger; result = extractor.read(input, null); } } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { Util.closeQuietly(dataSource); } } + private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec) + throws IOException { + long bytesToRead = dataSource.open(dataSpec); + + if (extractor == null) { + Pair extractorData = + extractorFactory.createExtractor( + previousExtractor, + dataSpec.uri, + trackFormat, + muxedCaptionFormats, + drmInitData, + timestampAdjuster, + dataSource.getResponseHeaders()); + extractor = extractorData.first; + isPackedAudioExtractor = extractorData.second; + boolean reusingExtractor = extractor == previousExtractor; + initLoadCompleted = reusingExtractor && initDataSpec != null; + if (isPackedAudioExtractor && id3Data == null) { + id3Decoder = new Id3Decoder(); + id3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH); + } + output.init(uid, shouldSpliceIn, reusingExtractor); + if (!reusingExtractor) { + extractor.init(output); + } + } + + return new DefaultExtractorInput(dataSource, dataSpec.absoluteStreamPosition, bytesToRead); + } + /** * Peek the presentation timestamp of the first sample in the chunk from an ID3 PRIV as defined * in the HLS spec, version 20, Section 3.4. Returns {@link C#TIME_UNSET} if the frame is not diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 5071ec366..1beb7e2e5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -13,26 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistTracker; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -49,6 +55,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final HlsExtractorFactory extractorFactory; private final HlsPlaylistTracker playlistTracker; private final HlsDataSourceFactory dataSourceFactory; + private final @Nullable TransferListener mediaTransferListener; + private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; private final int minLoadableRetryCount; private final EventDispatcher eventDispatcher; private final Allocator allocator; @@ -57,7 +65,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private final boolean allowChunklessPreparation; - private Callback callback; + private @Nullable Callback callback; private int pendingPrepareCount; private TrackGroupArray trackGroups; private HlsSampleStreamWrapper[] sampleStreamWrappers; @@ -65,10 +73,29 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private SequenceableLoader compositeSequenceableLoader; private boolean notifiedReadingStarted; + /** + * Creates an HLS media period. + * + * @param extractorFactory An {@link HlsExtractorFactory} for {@link Extractor}s for the segments. + * @param playlistTracker A tracker for HLS playlists. + * @param dataSourceFactory An {@link HlsDataSourceFactory} for {@link DataSource}s for segments + * and keys. + * @param mediaTransferListener The transfer listener to inform of any media data transfers. May + * be null if no listener is available. + * @param chunkLoadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy} for chunk loads. + * @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs. + * @param eventDispatcher A dispatcher to notify of events. + * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param compositeSequenceableLoaderFactory A factory to create composite {@link + * SequenceableLoader}s for when this media source loads data from multiple streams. + * @param allowChunklessPreparation Whether chunkless preparation is allowed. + */ public HlsMediaPeriod( HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker, HlsDataSourceFactory dataSourceFactory, + @Nullable TransferListener mediaTransferListener, + LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, int minLoadableRetryCount, EventDispatcher eventDispatcher, Allocator allocator, @@ -77,6 +104,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper this.extractorFactory = extractorFactory; this.playlistTracker = playlistTracker; this.dataSourceFactory = dataSourceFactory; + this.mediaTransferListener = mediaTransferListener; + this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; this.minLoadableRetryCount = minLoadableRetryCount; this.eventDispatcher = eventDispatcher; this.allocator = allocator; @@ -96,6 +125,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) { sampleStreamWrapper.release(); } + callback = null; eventDispatcher.mediaPeriodReleased(); } @@ -338,7 +368,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper C.TRACK_TYPE_AUDIO, new HlsUrl[] {audioRendition}, null, - Collections.emptyList(), + Collections.emptyList(), positionUs); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; Format renditionFormat = audioRendition.format; @@ -355,11 +385,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper HlsUrl url = subtitleRenditions.get(i); HlsSampleStreamWrapper sampleStreamWrapper = buildSampleStreamWrapper( - C.TRACK_TYPE_TEXT, - new HlsUrl[] {url}, - null, - Collections.emptyList(), - positionUs); + C.TRACK_TYPE_TEXT, new HlsUrl[] {url}, null, Collections.emptyList(), positionUs); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; sampleStreamWrapper.prepareWithMasterPlaylistInfo( new TrackGroupArray(new TrackGroup(url.format)), 0, TrackGroupArray.EMPTY); @@ -440,8 +466,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper && (masterPlaylist.muxedAudioFormat != null || masterPlaylist.audios.isEmpty())) { muxedTrackGroups.add( new TrackGroup( - deriveMuxedAudioFormat( - variants[0].format, masterPlaylist.muxedAudioFormat, Format.NO_VALUE))); + deriveAudioFormat( + variants[0].format, + masterPlaylist.muxedAudioFormat, + /* isPrimaryTrackInVariant= */ false))); } List ccFormats = masterPlaylist.muxedCaptionFormats; if (ccFormats != null) { @@ -455,8 +483,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper for (int i = 0; i < audioFormats.length; i++) { Format variantFormat = variants[i].format; audioFormats[i] = - deriveMuxedAudioFormat( - variantFormat, masterPlaylist.muxedAudioFormat, variantFormat.bitrate); + deriveAudioFormat( + variantFormat, + masterPlaylist.muxedAudioFormat, + /* isPrimaryTrackInVariant= */ true); } muxedTrackGroups.add(new TrackGroup(audioFormats)); } else { @@ -486,53 +516,78 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private HlsSampleStreamWrapper buildSampleStreamWrapper(int trackType, HlsUrl[] variants, Format muxedAudioFormat, List muxedCaptionFormats, long positionUs) { - HlsChunkSource defaultChunkSource = new HlsChunkSource(extractorFactory, playlistTracker, - variants, dataSourceFactory, timestampAdjusterProvider, muxedCaptionFormats); - return new HlsSampleStreamWrapper(trackType, this, defaultChunkSource, allocator, positionUs, - muxedAudioFormat, minLoadableRetryCount, eventDispatcher); + HlsChunkSource defaultChunkSource = + new HlsChunkSource( + extractorFactory, + playlistTracker, + variants, + dataSourceFactory, + mediaTransferListener, + timestampAdjusterProvider, + muxedCaptionFormats); + return new HlsSampleStreamWrapper( + trackType, + /* callback= */ this, + defaultChunkSource, + allocator, + positionUs, + muxedAudioFormat, + chunkLoadErrorHandlingPolicy, + minLoadableRetryCount, + eventDispatcher); } private static Format deriveVideoFormat(Format variantFormat) { String codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_VIDEO); - String mimeType = MimeTypes.getMediaMimeType(codecs); - return Format.createVideoSampleFormat( + String sampleMimeType = MimeTypes.getMediaMimeType(codecs); + return Format.createVideoContainerFormat( variantFormat.id, - mimeType, + variantFormat.label, + variantFormat.containerMimeType, + sampleMimeType, codecs, variantFormat.bitrate, - Format.NO_VALUE, variantFormat.width, variantFormat.height, variantFormat.frameRate, - null, - null); + /* initializationData= */ null, + variantFormat.selectionFlags); } - private static Format deriveMuxedAudioFormat( - Format variantFormat, Format mediaTagFormat, int bitrate) { + private static Format deriveAudioFormat( + Format variantFormat, Format mediaTagFormat, boolean isPrimaryTrackInVariant) { String codecs; int channelCount = Format.NO_VALUE; int selectionFlags = 0; String language = null; + String label = null; if (mediaTagFormat != null) { codecs = mediaTagFormat.codecs; channelCount = mediaTagFormat.channelCount; selectionFlags = mediaTagFormat.selectionFlags; language = mediaTagFormat.language; + label = mediaTagFormat.label; } else { codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_AUDIO); + if (isPrimaryTrackInVariant) { + channelCount = variantFormat.channelCount; + selectionFlags = variantFormat.selectionFlags; + language = variantFormat.label; + label = variantFormat.label; + } } - String mimeType = MimeTypes.getMediaMimeType(codecs); - return Format.createAudioSampleFormat( + String sampleMimeType = MimeTypes.getMediaMimeType(codecs); + int bitrate = isPrimaryTrackInVariant ? variantFormat.bitrate : Format.NO_VALUE; + return Format.createAudioContainerFormat( variantFormat.id, - mimeType, + label, + variantFormat.containerMimeType, + sampleMimeType, codecs, bitrate, - Format.NO_VALUE, channelCount, - Format.NO_VALUE, - null, - null, + /* sampleRate= */ Format.NO_VALUE, + /* initializationData= */ null, selectionFlags, language); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 283330649..112071f1f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -13,33 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.net.Uri; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.source.BaseMediaSource; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.SinglePeriodTimeline; -import org.telegram.messenger.exoplayer2.source.ads.AdsMediaSource; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistParser; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistTracker; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.source.BaseMediaSource; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.SinglePeriodTimeline; +import com.google.android.exoplayer2.source.ads.AdsMediaSource; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistTracker; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.List; @@ -58,7 +62,9 @@ public final class HlsMediaSource extends BaseMediaSource private HlsExtractorFactory extractorFactory; private @Nullable ParsingLoadable.Parser playlistParser; + private @Nullable HlsPlaylistTracker playlistTracker; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; + private LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; private int minLoadableRetryCount; private boolean allowChunklessPreparation; private boolean isCreateCalled; @@ -84,14 +90,15 @@ public final class HlsMediaSource extends BaseMediaSource public Factory(HlsDataSourceFactory hlsDataSourceFactory) { this.hlsDataSourceFactory = Assertions.checkNotNull(hlsDataSourceFactory); extractorFactory = HlsExtractorFactory.DEFAULT; + chunkLoadErrorHandlingPolicy = LoadErrorHandlingPolicy.getDefault(); minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT; compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory(); } /** * Sets a tag for the media source which will be published in the {@link - * org.telegram.messenger.exoplayer2.Timeline} of the source as {@link - * org.telegram.messenger.exoplayer2.Timeline.Window#tag}. + * com.google.android.exoplayer2.Timeline} of the source as {@link + * com.google.android.exoplayer2.Timeline.Window#tag}. * * @param tag A tag for the media source. * @return This factory, for convenience. @@ -118,6 +125,21 @@ public final class HlsMediaSource extends BaseMediaSource return this; } + /** + * Sets the {@link LoadErrorHandlingPolicy} for chunk loads. The default value is {@link + * LoadErrorHandlingPolicy#DEFAULT}. + * + * @param chunkLoadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy} for chunk loads. + * @return This factory, for convenience. + * @throws IllegalStateException If one of the {@code create} methods has already been called. + */ + public Factory setChunkLoadErrorHandlingPolicy( + LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy) { + Assertions.checkState(!isCreateCalled); + this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; + return this; + } + /** * Sets the minimum number of times to retry if a loading error occurs. The default value is * {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. @@ -136,16 +158,37 @@ public final class HlsMediaSource extends BaseMediaSource * Sets the parser to parse HLS playlists. The default is an instance of {@link * HlsPlaylistParser}. * + *

    Must not be called after calling {@link #setPlaylistTracker} on the same builder. + * * @param playlistParser A {@link ParsingLoadable.Parser} for HLS playlists. * @return This factory, for convenience. * @throws IllegalStateException If one of the {@code create} methods has already been called. */ public Factory setPlaylistParser(ParsingLoadable.Parser playlistParser) { Assertions.checkState(!isCreateCalled); + Assertions.checkState(playlistTracker == null, "A playlist tracker has already been set."); this.playlistParser = Assertions.checkNotNull(playlistParser); return this; } + /** + * Sets the HLS playlist tracker. The default is an instance of {@link + * DefaultHlsPlaylistTracker}. Playlist trackers must not be shared by {@link HlsMediaSource} + * instances. + * + *

    Must not be called after calling {@link #setPlaylistParser} on the same builder. + * + * @param playlistTracker A tracker for HLS playlists. + * @return This factory, for convenience. + * @throws IllegalStateException If one of the {@code create} methods has already been called. + */ + public Factory setPlaylistTracker(HlsPlaylistTracker playlistTracker) { + Assertions.checkState(!isCreateCalled); + Assertions.checkState(playlistParser == null, "A playlist parser has already been set."); + this.playlistTracker = Assertions.checkNotNull(playlistTracker); + return this; + } + /** * Sets the factory to create composite {@link SequenceableLoader}s for when this media source * loads data from multiple streams (video, audio etc...). The default is an instance of {@link @@ -187,16 +230,22 @@ public final class HlsMediaSource extends BaseMediaSource @Override public HlsMediaSource createMediaSource(Uri playlistUri) { isCreateCalled = true; - if (playlistParser == null) { - playlistParser = new HlsPlaylistParser(); + if (playlistTracker == null) { + playlistTracker = + new DefaultHlsPlaylistTracker( + hlsDataSourceFactory, + LoadErrorHandlingPolicy.getDefault(), + minLoadableRetryCount, + playlistParser != null ? playlistParser : new HlsPlaylistParser()); } return new HlsMediaSource( playlistUri, hlsDataSourceFactory, extractorFactory, compositeSequenceableLoaderFactory, + chunkLoadErrorHandlingPolicy, minLoadableRetryCount, - playlistParser, + playlistTracker, allowChunklessPreparation, tag); } @@ -232,12 +281,13 @@ public final class HlsMediaSource extends BaseMediaSource private final Uri manifestUri; private final HlsDataSourceFactory dataSourceFactory; private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; + private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; private final int minLoadableRetryCount; - private final ParsingLoadable.Parser playlistParser; private final boolean allowChunklessPreparation; + private final HlsPlaylistTracker playlistTracker; private final @Nullable Object tag; - private HlsPlaylistTracker playlistTracker; + private @Nullable TransferListener mediaTransferListener; /** * @param manifestUri The {@link Uri} of the HLS manifest. @@ -276,8 +326,13 @@ public final class HlsMediaSource extends BaseMediaSource int minLoadableRetryCount, Handler eventHandler, MediaSourceEventListener eventListener) { - this(manifestUri, new DefaultHlsDataSourceFactory(dataSourceFactory), - HlsExtractorFactory.DEFAULT, minLoadableRetryCount, eventHandler, eventListener, + this( + manifestUri, + new DefaultHlsDataSourceFactory(dataSourceFactory), + HlsExtractorFactory.DEFAULT, + minLoadableRetryCount, + eventHandler, + eventListener, new HlsPlaylistParser()); } @@ -308,8 +363,13 @@ public final class HlsMediaSource extends BaseMediaSource dataSourceFactory, extractorFactory, new DefaultCompositeSequenceableLoaderFactory(), + LoadErrorHandlingPolicy.getDefault(), minLoadableRetryCount, - playlistParser, + new DefaultHlsPlaylistTracker( + dataSourceFactory, + LoadErrorHandlingPolicy.getDefault(), + minLoadableRetryCount, + playlistParser), /* allowChunklessPreparation= */ false, /* tag= */ null); if (eventHandler != null && eventListener != null) { @@ -322,26 +382,30 @@ public final class HlsMediaSource extends BaseMediaSource HlsDataSourceFactory dataSourceFactory, HlsExtractorFactory extractorFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, + LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, int minLoadableRetryCount, - ParsingLoadable.Parser playlistParser, + HlsPlaylistTracker playlistTracker, boolean allowChunklessPreparation, @Nullable Object tag) { this.manifestUri = manifestUri; this.dataSourceFactory = dataSourceFactory; this.extractorFactory = extractorFactory; this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory; + this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; this.minLoadableRetryCount = minLoadableRetryCount; - this.playlistParser = playlistParser; + this.playlistTracker = playlistTracker; this.allowChunklessPreparation = allowChunklessPreparation; this.tag = tag; } @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + this.mediaTransferListener = mediaTransferListener; EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null); - playlistTracker = new HlsPlaylistTracker(manifestUri, dataSourceFactory, eventDispatcher, - minLoadableRetryCount, this, playlistParser); - playlistTracker.start(); + playlistTracker.start(manifestUri, eventDispatcher, /* listener= */ this); } @Override @@ -357,6 +421,8 @@ public final class HlsMediaSource extends BaseMediaSource extractorFactory, playlistTracker, dataSourceFactory, + mediaTransferListener, + chunkLoadErrorHandlingPolicy, minLoadableRetryCount, eventDispatcher, allocator, @@ -372,8 +438,7 @@ public final class HlsMediaSource extends BaseMediaSource @Override public void releaseSourceInternal() { if (playlistTracker != null) { - playlistTracker.release(); - playlistTracker = null; + playlistTracker.stop(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java index 30b5c824d..f43d11901 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStreamWrapper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index e0b7c72c9..73114f43c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -13,41 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.os.Handler; -import android.support.annotation.IntDef; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.extractor.DummyTrackOutput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SampleQueue; -import org.telegram.messenger.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.chunk.Chunk; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.extractor.DummyTrackOutput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * Loads {@link HlsMediaChunk}s obtained from a {@link HlsChunkSource}, and provides @@ -80,25 +80,18 @@ import java.util.Arrays; public static final int SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL = -2; public static final int SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL = -3; - @Retention(RetentionPolicy.SOURCE) - @IntDef({PRIMARY_TYPE_NONE, PRIMARY_TYPE_TEXT, PRIMARY_TYPE_AUDIO, PRIMARY_TYPE_VIDEO}) - private @interface PrimaryTrackType {} - - private static final int PRIMARY_TYPE_NONE = 0; - private static final int PRIMARY_TYPE_TEXT = 1; - private static final int PRIMARY_TYPE_AUDIO = 2; - private static final int PRIMARY_TYPE_VIDEO = 3; - private final int trackType; private final Callback callback; private final HlsChunkSource chunkSource; private final Allocator allocator; private final Format muxedAudioFormat; + private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; private final int minLoadableRetryCount; private final Loader loader; private final EventDispatcher eventDispatcher; private final HlsChunkSource.HlsChunkHolder nextChunkHolder; private final ArrayList mediaChunks; + private final List readOnlyMediaChunks; private final Runnable maybeFinishPrepareRunnable; private final Runnable onTracksEndedRunnable; private final Handler handler; @@ -110,9 +103,12 @@ import java.util.Arrays; private int audioSampleQueueIndex; private boolean videoSampleQueueMappingDone; private int videoSampleQueueIndex; + private int primarySampleQueueType; + private int primarySampleQueueIndex; private boolean sampleQueuesBuilt; private boolean prepared; private int enabledTrackGroupCount; + private Format upstreamTrackFormat; private Format downstreamTrackFormat; private boolean released; @@ -136,6 +132,7 @@ import java.util.Arrays; // Accessed only by the loading thread. private boolean tracksEnded; private long sampleOffsetUs; + private int chunkUid; /** * @param trackType The type of the track. One of the {@link C} {@code TRACK_TYPE_*} constants. @@ -144,18 +141,27 @@ import java.util.Arrays; * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param positionUs The position from which to start loading media. * @param muxedAudioFormat Optional muxed audio {@link Format} as defined by the master playlist. + * @param chunkLoadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy} for chunk loads. * @param minLoadableRetryCount The minimum number of times that the source should retry a load * before propagating an error. * @param eventDispatcher A dispatcher to notify of events. */ - public HlsSampleStreamWrapper(int trackType, Callback callback, HlsChunkSource chunkSource, - Allocator allocator, long positionUs, Format muxedAudioFormat, int minLoadableRetryCount, + public HlsSampleStreamWrapper( + int trackType, + Callback callback, + HlsChunkSource chunkSource, + Allocator allocator, + long positionUs, + Format muxedAudioFormat, + LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, + int minLoadableRetryCount, EventDispatcher eventDispatcher) { this.trackType = trackType; this.callback = callback; this.chunkSource = chunkSource; this.allocator = allocator; this.muxedAudioFormat = muxedAudioFormat; + this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; this.minLoadableRetryCount = minLoadableRetryCount; this.eventDispatcher = eventDispatcher; loader = new Loader("Loader:HlsSampleStreamWrapper"); @@ -167,21 +173,10 @@ import java.util.Arrays; sampleQueueIsAudioVideoFlags = new boolean[0]; sampleQueuesEnabledStates = new boolean[0]; mediaChunks = new ArrayList<>(); + readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); hlsSampleStreams = new ArrayList<>(); - maybeFinishPrepareRunnable = - new Runnable() { - @Override - public void run() { - maybeFinishPrepare(); - } - }; - onTracksEndedRunnable = - new Runnable() { - @Override - public void run() { - onTracksEnded(); - } - }; + maybeFinishPrepareRunnable = this::maybeFinishPrepare; + onTracksEndedRunnable = this::onTracksEnded; handler = new Handler(); lastSeekPositionUs = positionUs; pendingResetPositionUs = positionUs; @@ -467,8 +462,23 @@ import java.util.Arrays; downstreamTrackFormat = trackFormat; } - return sampleQueues[sampleQueueIndex].read(formatHolder, buffer, requireFormat, loadingFinished, - lastSeekPositionUs); + int result = + sampleQueues[sampleQueueIndex].read( + formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs); + if (result == C.RESULT_FORMAT_READ && sampleQueueIndex == primarySampleQueueIndex) { + // Fill in primary sample format with information from the track format. + int chunkUid = sampleQueues[sampleQueueIndex].peekSourceId(); + int chunkIndex = 0; + while (chunkIndex < mediaChunks.size() && mediaChunks.get(chunkIndex).uid != chunkUid) { + chunkIndex++; + } + Format trackFormat = + chunkIndex < mediaChunks.size() + ? mediaChunks.get(chunkIndex).trackFormat + : upstreamTrackFormat; + formatHolder.format = formatHolder.format.copyWithManifestFormatInfo(trackFormat); + } + return result; } public int skipData(int sampleQueueIndex, long positionUs) { @@ -526,16 +536,16 @@ import java.util.Arrays; return false; } - HlsMediaChunk previousChunk; + List chunkQueue; long loadPositionUs; if (isPendingReset()) { - previousChunk = null; + chunkQueue = Collections.emptyList(); loadPositionUs = pendingResetPositionUs; } else { - previousChunk = getLastMediaChunk(); - loadPositionUs = previousChunk.endTimeUs; + chunkQueue = readOnlyMediaChunks; + loadPositionUs = getLastMediaChunk().endTimeUs; } - chunkSource.getNextChunk(previousChunk, positionUs, loadPositionUs, nextChunkHolder); + chunkSource.getNextChunk(positionUs, loadPositionUs, chunkQueue, nextChunkHolder); boolean endOfStream = nextChunkHolder.endOfStream; Chunk loadable = nextChunkHolder.chunk; HlsMasterPlaylist.HlsUrl playlistToLoad = nextChunkHolder.playlist; @@ -559,11 +569,20 @@ import java.util.Arrays; HlsMediaChunk mediaChunk = (HlsMediaChunk) loadable; mediaChunk.init(this); mediaChunks.add(mediaChunk); + upstreamTrackFormat = mediaChunk.trackFormat; } long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount); - eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, - loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, - loadable.endTimeUs, elapsedRealtimeMs); + eventDispatcher.loadStarted( + loadable.dataSpec, + loadable.dataSpec.uri, + loadable.type, + trackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs); return true; } @@ -577,9 +596,19 @@ import java.util.Arrays; @Override public void onLoadCompleted(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs) { chunkSource.onChunkLoadCompleted(loadable); - eventDispatcher.loadCompleted(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, - loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, - loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); + eventDispatcher.loadCompleted( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + trackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded()); if (!prepared) { continueLoading(lastSeekPositionUs); } else { @@ -590,9 +619,19 @@ import java.util.Arrays; @Override public void onLoadCanceled(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released) { - eventDispatcher.loadCanceled(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, - loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, - loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); + eventDispatcher.loadCanceled( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + trackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded()); if (!released) { resetSampleQueues(); if (enabledTrackGroupCount > 0) { @@ -602,13 +641,27 @@ import java.util.Arrays; } @Override - public @Loader.RetryAction int onLoadError( - Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { + public LoadErrorAction onLoadError( + Chunk loadable, + long elapsedRealtimeMs, + long loadDurationMs, + IOException error, + int errorCount) { long bytesLoaded = loadable.bytesLoaded(); boolean isMediaChunk = isMediaChunk(loadable); - boolean cancelable = !isMediaChunk || bytesLoaded == 0; - boolean canceled = false; - if (chunkSource.onChunkLoadError(loadable, cancelable, error)) { + boolean blacklistSucceeded = false; + LoadErrorAction loadErrorAction; + + if (!isMediaChunk || bytesLoaded == 0) { + long blacklistDurationMs = + chunkLoadErrorHandlingPolicy.getBlacklistDurationMsFor( + loadable, loadDurationMs, error, errorCount); + if (blacklistDurationMs != C.TIME_UNSET) { + blacklistSucceeded = chunkSource.maybeBlacklistTrack(loadable, blacklistDurationMs); + } + } + + if (blacklistSucceeded) { if (isMediaChunk) { HlsMediaChunk removed = mediaChunks.remove(mediaChunks.size() - 1); Assertions.checkState(removed == loadable); @@ -616,22 +669,41 @@ import java.util.Arrays; pendingResetPositionUs = lastSeekPositionUs; } } - canceled = true; + loadErrorAction = Loader.DONT_RETRY; + } else /* did not blacklist */ { + long retryDelayMs = + chunkLoadErrorHandlingPolicy.getRetryDelayMsFor( + loadable, loadDurationMs, error, errorCount); + loadErrorAction = + retryDelayMs != C.TIME_UNSET + ? Loader.createRetryAction(/* resetErrorCount= */ false, retryDelayMs) + : Loader.DONT_RETRY_FATAL; } - eventDispatcher.loadError(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, - loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, - loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded(), error, - canceled); - if (canceled) { + + eventDispatcher.loadError( + loadable.dataSpec, + loadable.getUri(), + loadable.type, + trackType, + loadable.trackFormat, + loadable.trackSelectionReason, + loadable.trackSelectionData, + loadable.startTimeUs, + loadable.endTimeUs, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded(), + error, + /* wasCanceled= */ !loadErrorAction.isRetry()); + + if (blacklistSucceeded) { if (!prepared) { continueLoading(lastSeekPositionUs); } else { callback.onContinueLoadingRequested(this); } - return Loader.DONT_RETRY; - } else { - return error instanceof ParserException ? Loader.DONT_RETRY_FATAL : Loader.RETRY; } + return loadErrorAction; } // Called by the consuming thread, but only when there is no loading thread. @@ -650,6 +722,7 @@ import java.util.Arrays; audioSampleQueueMappingDone = false; videoSampleQueueMappingDone = false; } + this.chunkUid = chunkUid; for (SampleQueue sampleQueue : sampleQueues) { sampleQueue.sourceId(chunkUid); } @@ -705,6 +778,7 @@ import java.util.Arrays; } SampleQueue trackOutput = new SampleQueue(allocator); trackOutput.setSampleOffsetUs(sampleOffsetUs); + trackOutput.sourceId(chunkUid); trackOutput.setUpstreamFormatChangeListener(this); sampleQueueTrackIds = Arrays.copyOf(sampleQueueTrackIds, trackCount + 1); sampleQueueTrackIds[trackCount] = id; @@ -721,6 +795,10 @@ import java.util.Arrays; videoSampleQueueMappingDone = true; videoSampleQueueIndex = trackCount; } + if (getTrackTypeScore(type) > getTrackTypeScore(primarySampleQueueType)) { + primarySampleQueueIndex = trackCount; + primarySampleQueueType = type; + } sampleQueuesEnabledStates = Arrays.copyOf(sampleQueuesEnabledStates, trackCount + 1); return trackOutput; } @@ -858,22 +936,22 @@ import java.util.Arrays; private void buildTracksFromSampleStreams() { // Iterate through the extractor tracks to discover the "primary" track type, and the index // of the single track of this type. - @PrimaryTrackType int primaryExtractorTrackType = PRIMARY_TYPE_NONE; + int primaryExtractorTrackType = C.TRACK_TYPE_NONE; int primaryExtractorTrackIndex = C.INDEX_UNSET; int extractorTrackCount = sampleQueues.length; for (int i = 0; i < extractorTrackCount; i++) { String sampleMimeType = sampleQueues[i].getUpstreamFormat().sampleMimeType; - @PrimaryTrackType int trackType; + int trackType; if (MimeTypes.isVideo(sampleMimeType)) { - trackType = PRIMARY_TYPE_VIDEO; + trackType = C.TRACK_TYPE_VIDEO; } else if (MimeTypes.isAudio(sampleMimeType)) { - trackType = PRIMARY_TYPE_AUDIO; + trackType = C.TRACK_TYPE_AUDIO; } else if (MimeTypes.isText(sampleMimeType)) { - trackType = PRIMARY_TYPE_TEXT; + trackType = C.TRACK_TYPE_TEXT; } else { - trackType = PRIMARY_TYPE_NONE; + trackType = C.TRACK_TYPE_NONE; } - if (trackType > primaryExtractorTrackType) { + if (getTrackTypeScore(trackType) > getTrackTypeScore(primaryExtractorTrackType)) { primaryExtractorTrackType = trackType; primaryExtractorTrackIndex = i; } else if (trackType == primaryExtractorTrackType @@ -900,14 +978,21 @@ import java.util.Arrays; Format sampleFormat = sampleQueues[i].getUpstreamFormat(); if (i == primaryExtractorTrackIndex) { Format[] formats = new Format[chunkSourceTrackCount]; - for (int j = 0; j < chunkSourceTrackCount; j++) { - formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat, true); + if (chunkSourceTrackCount == 1) { + formats[0] = sampleFormat.copyWithManifestFormatInfo(chunkSourceTrackGroup.getFormat(0)); + } else { + for (int j = 0; j < chunkSourceTrackCount; j++) { + formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat, true); + } } trackGroups[i] = new TrackGroup(formats); primaryTrackGroupIndex = i; } else { - Format trackFormat = primaryExtractorTrackType == PRIMARY_TYPE_VIDEO - && MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null; + Format trackFormat = + primaryExtractorTrackType == C.TRACK_TYPE_VIDEO + && MimeTypes.isAudio(sampleFormat.sampleMimeType) + ? muxedAudioFormat + : null; trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat, false)); } } @@ -949,7 +1034,28 @@ import java.util.Arrays; } /** - * Derives a track format using master playlist and sample format information. + * Scores a track type. Where multiple tracks are muxed into a container, the track with the + * highest score is the primary track. + * + * @param trackType The track type. + * @return The score. + */ + private static int getTrackTypeScore(int trackType) { + switch (trackType) { + case C.TRACK_TYPE_VIDEO: + return 3; + case C.TRACK_TYPE_AUDIO: + return 2; + case C.TRACK_TYPE_TEXT: + return 1; + default: + return 0; + } + } + + /** + * Derives a track sample format from the corresponding format in the master playlist, and a + * sample format that may have been obtained from a chunk belonging to a different track. * * @param playlistFormat The format information obtained from the master playlist. * @param sampleFormat The format information obtained from the samples. @@ -971,6 +1077,7 @@ import java.util.Arrays; } return sampleFormat.copyWithContainerInfo( playlistFormat.id, + playlistFormat.label, mimeType, codecs, bitrate, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/SampleQueueMappingException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/SampleQueueMappingException.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/SampleQueueMappingException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/SampleQueueMappingException.java index f2bd5e0fd..9c9cb532a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/SampleQueueMappingException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/SampleQueueMappingException.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.source.SampleQueue; -import org.telegram.messenger.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.TrackGroup; import java.io.IOException; /** Thrown when it is not possible to map a {@link TrackGroup} to a {@link SampleQueue}. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/TimestampAdjusterProvider.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/TimestampAdjusterProvider.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java index af3b72d9a..85a4276ea 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/TimestampAdjusterProvider.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.util.TimestampAdjuster; /** * Provides {@link TimestampAdjuster} instances for use during HLS playbacks. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/WebvttExtractor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/WebvttExtractor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java index 69b55f592..0b8f7f36a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/WebvttExtractor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java @@ -13,23 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls; +package com.google.android.exoplayer2.source.hls; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.ExtractorOutput; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.text.webvtt.WebvttParserUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.TimestampAdjuster; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.text.webvtt.WebvttParserUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.io.IOException; import java.util.Arrays; import java.util.regex.Matcher; diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadAction.java new file mode 100755 index 000000000..c54a9a7dd --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadAction.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.hls.offline; + +import android.net.Uri; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.offline.DownloadAction; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloadAction; +import com.google.android.exoplayer2.offline.StreamKey; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** An action to download or remove downloaded HLS streams. */ +public final class HlsDownloadAction extends SegmentDownloadAction { + + private static final String TYPE = "hls"; + private static final int VERSION = 1; + + public static final Deserializer DESERIALIZER = + new SegmentDownloadActionDeserializer(TYPE, VERSION) { + + @Override + protected StreamKey readKey(int version, DataInputStream input) throws IOException { + if (version > 0) { + return super.readKey(version, input); + } + int renditionGroup = input.readInt(); + int trackIndex = input.readInt(); + return new StreamKey(renditionGroup, trackIndex); + } + + @Override + protected DownloadAction createDownloadAction( + Uri uri, boolean isRemoveAction, byte[] data, List keys) { + return new HlsDownloadAction(uri, isRemoveAction, data, keys); + } + }; + + /** + * Creates a HLS download action. + * + * @param uri The URI of the media to be downloaded. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + * @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded. + */ + public static HlsDownloadAction createDownloadAction( + Uri uri, @Nullable byte[] data, List keys) { + return new HlsDownloadAction(uri, /* isRemoveAction= */ false, data, keys); + } + + /** + * Creates a HLS remove action. + * + * @param uri The URI of the media to be removed. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + */ + public static HlsDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) { + return new HlsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + } + + /** + * @param uri The HLS playlist URI. + * @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded. + * @param data Optional custom data for this action. + * @param keys Keys of renditions to be downloaded. If empty, all renditions are downloaded. If + * {@code removeAction} is true, {@code keys} must empty. + * @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link + * #createRemoveAction(Uri, byte[])}. + */ + @Deprecated + public HlsDownloadAction( + Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { + super(TYPE, VERSION, uri, isRemoveAction, data, keys); + } + + @Override + public HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { + return new HlsDownloader(uri, keys, constructorHelper); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadHelper.java similarity index 63% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadHelper.java index d2f197a81..fcbe06993 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloadHelper.java @@ -13,28 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.offline; +package com.google.android.exoplayer2.source.hls.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.offline.DownloadHelper; -import org.telegram.messenger.exoplayer2.offline.TrackKey; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistParser; -import org.telegram.messenger.exoplayer2.source.hls.playlist.RenditionKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.offline.DownloadHelper; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.offline.TrackKey; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** A {@link DownloadHelper} for HLS streams. */ public final class HlsDownloadHelper extends DownloadHelper { @@ -42,8 +43,8 @@ public final class HlsDownloadHelper extends DownloadHelper { private final Uri uri; private final DataSource.Factory manifestDataSourceFactory; - private HlsPlaylist playlist; - private int[] renditionTypes; + private @MonotonicNonNull HlsPlaylist playlist; + private int[] renditionGroups; public HlsDownloadHelper(Uri uri, DataSource.Factory manifestDataSourceFactory) { this.uri = uri; @@ -53,7 +54,7 @@ public final class HlsDownloadHelper extends DownloadHelper { @Override protected void prepareInternal() throws IOException { DataSource dataSource = manifestDataSourceFactory.createDataSource(); - playlist = ParsingLoadable.load(dataSource, new HlsPlaylistParser(), uri); + playlist = ParsingLoadable.load(dataSource, new HlsPlaylistParser(), uri, C.DATA_TYPE_MANIFEST); } /** Returns the HLS playlist. Must not be called until after preparation completes. */ @@ -72,23 +73,24 @@ public final class HlsDownloadHelper extends DownloadHelper { public TrackGroupArray getTrackGroups(int periodIndex) { Assertions.checkNotNull(playlist); if (playlist instanceof HlsMediaPlaylist) { + renditionGroups = new int[0]; return TrackGroupArray.EMPTY; } // TODO: Generate track groups as in playback. Reverse the mapping in getDownloadAction. HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist; TrackGroup[] trackGroups = new TrackGroup[3]; - renditionTypes = new int[3]; + renditionGroups = new int[3]; int trackGroupIndex = 0; if (!masterPlaylist.variants.isEmpty()) { - renditionTypes[trackGroupIndex] = RenditionKey.TYPE_VARIANT; + renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_VARIANT; trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.variants)); } if (!masterPlaylist.audios.isEmpty()) { - renditionTypes[trackGroupIndex] = RenditionKey.TYPE_AUDIO; + renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_AUDIO; trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.audios)); } if (!masterPlaylist.subtitles.isEmpty()) { - renditionTypes[trackGroupIndex] = RenditionKey.TYPE_SUBTITLE; + renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_SUBTITLE; trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.subtitles)); } return new TrackGroupArray(Arrays.copyOf(trackGroups, trackGroupIndex)); @@ -96,15 +98,14 @@ public final class HlsDownloadHelper extends DownloadHelper { @Override public HlsDownloadAction getDownloadAction(@Nullable byte[] data, List trackKeys) { - Assertions.checkNotNull(renditionTypes); - return new HlsDownloadAction( - uri, /* isRemoveAction= */ false, data, toRenditionKeys(trackKeys, renditionTypes)); + Assertions.checkNotNull(renditionGroups); + return HlsDownloadAction.createDownloadAction( + uri, data, toStreamKeys(trackKeys, renditionGroups)); } @Override public HlsDownloadAction getRemoveAction(@Nullable byte[] data) { - return new HlsDownloadAction( - uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + return HlsDownloadAction.createRemoveAction(uri, data); } private static Format[] toFormats(List hlsUrls) { @@ -115,11 +116,11 @@ public final class HlsDownloadHelper extends DownloadHelper { return formats; } - private static List toRenditionKeys(List trackKeys, int[] groups) { - List representationKeys = new ArrayList<>(trackKeys.size()); + private static List toStreamKeys(List trackKeys, int[] groups) { + List representationKeys = new ArrayList<>(trackKeys.size()); for (int i = 0; i < trackKeys.size(); i++) { TrackKey trackKey = trackKeys.get(i); - representationKeys.add(new RenditionKey(groups[trackKey.groupIndex], trackKey.trackIndex)); + representationKeys.add(new StreamKey(groups[trackKey.groupIndex], trackKey.trackIndex)); } return representationKeys; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java index 55e3c54dd..85f41df35 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java @@ -13,22 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.offline; +package com.google.android.exoplayer2.source.hls.offline; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloader; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylist; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsPlaylistParser; -import org.telegram.messenger.exoplayer2.source.hls.playlist.RenditionKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloader; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.UriUtil; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; @@ -48,7 +48,7 @@ import java.util.List; * HlsDownloader hlsDownloader = * new HlsDownloader( * playlistUri, - * Collections.singletonList(new RenditionKey(RenditionKey.TYPE_VARIANT, 0)), + * Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)), * constructorHelper); * // Perform the download. * hlsDownloader.download(); @@ -57,19 +57,17 @@ import java.util.List; * new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE); * } */ -public final class HlsDownloader extends SegmentDownloader { +public final class HlsDownloader extends SegmentDownloader { /** * @param playlistUri The {@link Uri} of the playlist to be downloaded. - * @param renditionKeys Keys defining which renditions in the playlist should be selected for + * @param streamKeys Keys defining which renditions in the playlist should be selected for * download. If empty, all renditions are downloaded. * @param constructorHelper A {@link DownloaderConstructorHelper} instance. */ public HlsDownloader( - Uri playlistUri, - List renditionKeys, - DownloaderConstructorHelper constructorHelper) { - super(playlistUri, renditionKeys, constructorHelper); + Uri playlistUri, List streamKeys, DownloaderConstructorHelper constructorHelper) { + super(playlistUri, streamKeys, constructorHelper); } @Override @@ -120,10 +118,7 @@ public final class HlsDownloader extends SegmentDownloader loadable = - new ParsingLoadable<>(dataSource, uri, C.DATA_TYPE_MANIFEST, new HlsPlaylistParser()); - loadable.load(); - return loadable.getResult(); + return ParsingLoadable.load(dataSource, new HlsPlaylistParser(), uri, C.DATA_TYPE_MANIFEST); } private static void addSegment( diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java similarity index 59% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index e7f66b38b..099002a10 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -13,97 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.playlist; +package com.google.android.exoplayer2.source.hls.playlist; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; -import org.telegram.messenger.exoplayer2.source.hls.HlsDataSourceFactory; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; +import com.google.android.exoplayer2.source.hls.HlsDataSourceFactory; +import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.UriUtil; import java.io.IOException; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; -/** - * Tracks playlists linked to a provided playlist url. The provided url might reference an HLS - * master playlist or a media playlist. - */ -public final class HlsPlaylistTracker implements Loader.Callback> { - - /** - * Thrown when a playlist is considered to be stuck due to a server side error. - */ - public static final class PlaylistStuckException extends IOException { - - /** - * The url of the stuck playlist. - */ - public final String url; - - private PlaylistStuckException(String url) { - this.url = url; - } - - } - - /** - * Thrown when the media sequence of a new snapshot indicates the server has reset. - */ - public static final class PlaylistResetException extends IOException { - - /** - * The url of the reset playlist. - */ - public final String url; - - private PlaylistResetException(String url) { - this.url = url; - } - - } - - /** - * Listener for primary playlist changes. - */ - public interface PrimaryPlaylistListener { - - /** - * Called when the primary playlist changes. - * - * @param mediaPlaylist The primary playlist new snapshot. - */ - void onPrimaryPlaylistRefreshed(HlsMediaPlaylist mediaPlaylist); - } - - /** - * Called on playlist loading events. - */ - public interface PlaylistEventListener { - - /** - * Called a playlist changes. - */ - void onPlaylistChanged(); - - /** - * Called if an error is encountered while loading a playlist. - * - * @param url The loaded url that caused the error. - * @param shouldBlacklist Whether the playlist should be blacklisted. - * @return True if blacklisting did not encounter errors. False otherwise. - */ - boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist); - } +/** Default implementation for {@link HlsPlaylistTracker}. */ +public final class DefaultHlsPlaylistTracker + implements HlsPlaylistTracker, Loader.Callback> { /** * Coefficient applied on the target duration of a playlist to determine the amount of time after @@ -111,17 +47,18 @@ public final class HlsPlaylistTracker implements Loader.Callback playlistParser; + private final LoadErrorHandlingPolicy> + playlistLoadErrorHandlingPolicy; private final int minRetryCount; private final IdentityHashMap playlistBundles; - private final Handler playlistRefreshHandler; - private final PrimaryPlaylistListener primaryPlaylistListener; private final List listeners; - private final Loader initialPlaylistLoader; - private final EventDispatcher eventDispatcher; + private EventDispatcher eventDispatcher; + private Loader initialPlaylistLoader; + private Handler playlistRefreshHandler; + private PrimaryPlaylistListener primaryPlaylistListener; private HlsMasterPlaylist masterPlaylist; private HlsUrl primaryHlsUrl; private HlsMediaPlaylist primaryUrlSnapshot; @@ -129,77 +66,86 @@ public final class HlsPlaylistTracker implements Loader.Callback> playlistLoadErrorHandlingPolicy, + int minRetryCount, ParsingLoadable.Parser playlistParser) { - this.initialPlaylistUri = initialPlaylistUri; this.dataSourceFactory = dataSourceFactory; - this.eventDispatcher = eventDispatcher; this.minRetryCount = minRetryCount; - this.primaryPlaylistListener = primaryPlaylistListener; this.playlistParser = playlistParser; + this.playlistLoadErrorHandlingPolicy = playlistLoadErrorHandlingPolicy; listeners = new ArrayList<>(); - initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist"); playlistBundles = new IdentityHashMap<>(); - playlistRefreshHandler = new Handler(); initialStartTimeUs = C.TIME_UNSET; } - /** - * Registers a listener to receive events from the playlist tracker. - * - * @param listener The listener. - */ + // HlsPlaylistTracker implementation. + + @Override + public void start( + Uri initialPlaylistUri, + EventDispatcher eventDispatcher, + PrimaryPlaylistListener primaryPlaylistListener) { + this.playlistRefreshHandler = new Handler(); + this.eventDispatcher = eventDispatcher; + this.primaryPlaylistListener = primaryPlaylistListener; + ParsingLoadable masterPlaylistLoadable = + new ParsingLoadable<>( + dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST), + initialPlaylistUri, + C.DATA_TYPE_MANIFEST, + playlistParser); + Assertions.checkState(initialPlaylistLoader == null); + initialPlaylistLoader = new Loader("DefaultHlsPlaylistTracker:MasterPlaylist"); + long elapsedRealtime = + initialPlaylistLoader.startLoading(masterPlaylistLoadable, this, minRetryCount); + eventDispatcher.loadStarted( + masterPlaylistLoadable.dataSpec, + masterPlaylistLoadable.dataSpec.uri, + masterPlaylistLoadable.type, + elapsedRealtime); + } + + @Override + public void stop() { + primaryHlsUrl = null; + primaryUrlSnapshot = null; + masterPlaylist = null; + initialStartTimeUs = C.TIME_UNSET; + initialPlaylistLoader.release(); + initialPlaylistLoader = null; + for (MediaPlaylistBundle bundle : playlistBundles.values()) { + bundle.release(); + } + playlistRefreshHandler.removeCallbacksAndMessages(null); + playlistRefreshHandler = null; + playlistBundles.clear(); + } + + @Override public void addListener(PlaylistEventListener listener) { listeners.add(listener); } - /** - * Unregisters a listener. - * - * @param listener The listener to unregister. - */ + @Override public void removeListener(PlaylistEventListener listener) { listeners.remove(listener); } - /** - * Starts tracking all the playlists related to the provided Uri. - */ - public void start() { - ParsingLoadable masterPlaylistLoadable = new ParsingLoadable<>( - dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST), initialPlaylistUri, - C.DATA_TYPE_MANIFEST, playlistParser); - initialPlaylistLoader.startLoading(masterPlaylistLoadable, this, minRetryCount); - } - - /** - * Returns the master playlist. - * - * @return The master playlist. Null if the initial playlist has yet to be loaded. - */ + @Override public HlsMasterPlaylist getMasterPlaylist() { return masterPlaylist; } - /** - * Returns the most recent snapshot available of the playlist referenced by the provided - * {@link HlsUrl}. - * - * @param url The {@link HlsUrl} corresponding to the requested media playlist. - * @return The most recent snapshot of the playlist referenced by the provided {@link HlsUrl}. May - * be null if no snapshot has been loaded yet. - */ + @Override public HlsMediaPlaylist getPlaylistSnapshot(HlsUrl url) { HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot(); if (snapshot != null) { @@ -208,77 +154,37 @@ public final class HlsPlaylistTracker implements Loader.Callback loadable, long elapsedRealtimeMs, - long loadDurationMs) { + public void onLoadCompleted( + ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { HlsPlaylist result = loadable.getResult(); HlsMasterPlaylist masterPlaylist; boolean isMediaPlaylist = result instanceof HlsMediaPlaylist; @@ -310,27 +216,53 @@ public final class HlsPlaylistTracker implements Loader.Callback loadable, long elapsedRealtimeMs, - long loadDurationMs, boolean released) { - eventDispatcher.loadCanceled(loadable.dataSpec, C.DATA_TYPE_MANIFEST, elapsedRealtimeMs, - loadDurationMs, loadable.bytesLoaded()); - } - - @Override - public @Loader.RetryAction int onLoadError( + public void onLoadCanceled( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, - IOException error) { - boolean isFatal = error instanceof ParserException; - eventDispatcher.loadError(loadable.dataSpec, C.DATA_TYPE_MANIFEST, elapsedRealtimeMs, - loadDurationMs, loadable.bytesLoaded(), error, isFatal); - return isFatal ? Loader.DONT_RETRY_FATAL : Loader.RETRY; + boolean released) { + eventDispatcher.loadCanceled( + loadable.dataSpec, + loadable.getUri(), + C.DATA_TYPE_MANIFEST, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded()); + } + + @Override + public LoadErrorAction onLoadError( + ParsingLoadable loadable, + long elapsedRealtimeMs, + long loadDurationMs, + IOException error, + int errorCount) { + long retryDelayMs = + playlistLoadErrorHandlingPolicy.getRetryDelayMsFor( + loadable, loadDurationMs, error, errorCount); + boolean isFatal = retryDelayMs == C.TIME_UNSET; + eventDispatcher.loadError( + loadable.dataSpec, + loadable.getUri(), + C.DATA_TYPE_MANIFEST, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded(), + error, + isFatal); + return isFatal + ? Loader.DONT_RETRY_FATAL + : Loader.createRetryAction(/* resetErrorCount= */ false, retryDelayMs); } // Internal methods. @@ -402,8 +334,8 @@ public final class HlsPlaylistTracker implements Loader.Callback oldSegments = oldPlaylist.segments; return mediaSequenceOffset < oldSegments.size() ? oldSegments.get(mediaSequenceOffset) : null; } - /** - * Holds all information related to a specific Media Playlist. - */ - private final class MediaPlaylistBundle implements Loader.Callback>, - Runnable { + /** Holds all information related to a specific Media Playlist. */ + private final class MediaPlaylistBundle + implements Loader.Callback>, Runnable { private final HlsUrl playlistUrl; private final Loader mediaPlaylistLoader; @@ -489,11 +419,13 @@ public final class HlsPlaylistTracker implements Loader.Callback( - dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST), - UriUtil.resolveToUri(masterPlaylist.baseUri, playlistUrl.url), C.DATA_TYPE_MANIFEST, - playlistParser); + mediaPlaylistLoader = new Loader("DefaultHlsPlaylistTracker:MediaPlaylist"); + mediaPlaylistLoadable = + new ParsingLoadable<>( + dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST), + UriUtil.resolveToUri(masterPlaylist.baseUri, playlistUrl.url), + C.DATA_TYPE_MANIFEST, + playlistParser); } public HlsMediaPlaylist getPlaylistSnapshot() { @@ -541,44 +473,81 @@ public final class HlsPlaylistTracker implements Loader.Callback loadable, long elapsedRealtimeMs, - long loadDurationMs) { + public void onLoadCompleted( + ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { HlsPlaylist result = loadable.getResult(); if (result instanceof HlsMediaPlaylist) { processLoadedPlaylist((HlsMediaPlaylist) result); - eventDispatcher.loadCompleted(loadable.dataSpec, C.DATA_TYPE_MANIFEST, elapsedRealtimeMs, - loadDurationMs, loadable.bytesLoaded()); + eventDispatcher.loadCompleted( + loadable.dataSpec, + loadable.getUri(), + C.DATA_TYPE_MANIFEST, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded()); } else { playlistError = new ParserException("Loaded playlist has unexpected type."); } } @Override - public void onLoadCanceled(ParsingLoadable loadable, long elapsedRealtimeMs, - long loadDurationMs, boolean released) { - eventDispatcher.loadCanceled(loadable.dataSpec, C.DATA_TYPE_MANIFEST, elapsedRealtimeMs, - loadDurationMs, loadable.bytesLoaded()); - } - - @Override - public @Loader.RetryAction int onLoadError( + public void onLoadCanceled( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, - IOException error) { - boolean isFatal = error instanceof ParserException; - eventDispatcher.loadError(loadable.dataSpec, C.DATA_TYPE_MANIFEST, elapsedRealtimeMs, - loadDurationMs, loadable.bytesLoaded(), error, isFatal); - boolean shouldBlacklist = ChunkedTrackBlacklistUtil.shouldBlacklist(error); - boolean shouldRetryIfNotFatal = + boolean released) { + eventDispatcher.loadCanceled( + loadable.dataSpec, + loadable.getUri(), + C.DATA_TYPE_MANIFEST, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded()); + } + + @Override + public LoadErrorAction onLoadError( + ParsingLoadable loadable, + long elapsedRealtimeMs, + long loadDurationMs, + IOException error, + int errorCount) { + LoadErrorAction loadErrorAction; + + long blacklistDurationMs = + playlistLoadErrorHandlingPolicy.getBlacklistDurationMsFor( + loadable, loadDurationMs, error, errorCount); + boolean shouldBlacklist = blacklistDurationMs != C.TIME_UNSET; + + boolean blacklistingFailed = notifyPlaylistError(playlistUrl, shouldBlacklist) || !shouldBlacklist; - if (isFatal) { - return Loader.DONT_RETRY_FATAL; - } if (shouldBlacklist) { - shouldRetryIfNotFatal |= blacklistPlaylist(); + blacklistingFailed |= blacklistPlaylist(); } - return shouldRetryIfNotFatal ? Loader.RETRY : Loader.DONT_RETRY; + + if (blacklistingFailed) { + long retryDelay = + playlistLoadErrorHandlingPolicy.getRetryDelayMsFor( + loadable, loadDurationMs, error, errorCount); + loadErrorAction = + retryDelay != C.TIME_UNSET + ? Loader.createRetryAction(false, retryDelay) + : Loader.DONT_RETRY_FATAL; + } else { + loadErrorAction = Loader.DONT_RETRY; + } + + eventDispatcher.loadError( + loadable.dataSpec, + loadable.getUri(), + C.DATA_TYPE_MANIFEST, + elapsedRealtimeMs, + loadDurationMs, + loadable.bytesLoaded(), + error, + /* wasCanceled= */ !loadErrorAction.isRetry()); + + return loadErrorAction; } // Runnable implementation. @@ -592,10 +561,19 @@ public final class HlsPlaylistTracker implements Loader.Callback C.usToMs(playlistSnapshot.targetDurationUs) * PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) { + // TODO: Allow customization of stuck playlists handling. // The playlist seems to be stuck. Blacklist it. playlistError = new PlaylistStuckException(playlistUrl.url); notifyPlaylistError(playlistUrl, true); @@ -621,8 +601,12 @@ public final class HlsPlaylistTracker implements Loader.Callback tags, List variants, - List audios, List subtitles, Format muxedAudioFormat, - List muxedCaptionFormats) { - super(baseUri, tags); + public HlsMasterPlaylist( + String baseUri, + List tags, + List variants, + List audios, + List subtitles, + Format muxedAudioFormat, + List muxedCaptionFormats, + boolean hasIndependentSegments) { + super(baseUri, tags, hasIndependentSegments); this.variants = Collections.unmodifiableList(variants); this.audios = Collections.unmodifiableList(audios); this.subtitles = Collections.unmodifiableList(subtitles); @@ -108,15 +128,16 @@ public final class HlsMasterPlaylist extends HlsPlaylist { } @Override - public HlsMasterPlaylist copy(List renditionKeys) { + public HlsMasterPlaylist copy(List streamKeys) { return new HlsMasterPlaylist( baseUri, tags, - copyRenditionsList(variants, RenditionKey.TYPE_VARIANT, renditionKeys), - copyRenditionsList(audios, RenditionKey.TYPE_AUDIO, renditionKeys), - copyRenditionsList(subtitles, RenditionKey.TYPE_SUBTITLE, renditionKeys), + copyRenditionsList(variants, GROUP_INDEX_VARIANT, streamKeys), + copyRenditionsList(audios, GROUP_INDEX_AUDIO, streamKeys), + copyRenditionsList(subtitles, GROUP_INDEX_SUBTITLE, streamKeys), muxedAudioFormat, - muxedCaptionFormats); + muxedCaptionFormats, + hasIndependentSegments); } /** @@ -128,18 +149,25 @@ public final class HlsMasterPlaylist extends HlsPlaylist { public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) { List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl)); List emptyList = Collections.emptyList(); - return new HlsMasterPlaylist(null, Collections.emptyList(), variant, emptyList, - emptyList, null, null); + return new HlsMasterPlaylist( + null, + Collections.emptyList(), + variant, + emptyList, + emptyList, + /* muxedAudioFormat= */ null, + /* muxedCaptionFormats= */ null, + /* hasIndependentSegments= */ false); } private static List copyRenditionsList( - List renditions, int renditionType, List renditionKeys) { - List copiedRenditions = new ArrayList<>(renditionKeys.size()); + List renditions, int groupIndex, List streamKeys) { + List copiedRenditions = new ArrayList<>(streamKeys.size()); for (int i = 0; i < renditions.size(); i++) { HlsUrl rendition = renditions.get(i); - for (int j = 0; j < renditionKeys.size(); j++) { - RenditionKey renditionKey = renditionKeys.get(j); - if (renditionKey.type == renditionType && renditionKey.trackIndex == i) { + for (int j = 0; j < streamKeys.size(); j++) { + StreamKey streamKey = streamKeys.get(j); + if (streamKey.groupIndex == groupIndex && streamKey.trackIndex == i) { copiedRenditions.add(rendition); break; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 6e1e07f3e..2c34a5a35 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.playlist; +package com.google.android.exoplayer2.source.hls.playlist; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.offline.StreamKey; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; @@ -41,9 +42,11 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * the media playlist does not define a media section for this segment. The same instance is * used for all segments that share an EXT-X-MAP tag. */ - @Nullable public final Segment initializationSegment; + public final @Nullable Segment initializationSegment; /** The duration of the segment in microseconds, as defined by #EXTINF. */ public final long durationUs; + /** The human readable title of the segment. */ + public final String title; /** * The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment. */ @@ -56,12 +59,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * The encryption identity key uri as defined by #EXT-X-KEY, or null if the segment does not use * full segment encryption with identity key. */ - public final String fullSegmentEncryptionKeyUri; + public final @Nullable String fullSegmentEncryptionKeyUri; /** * The encryption initialization vector as defined by #EXT-X-KEY, or null if the segment is not * encrypted. */ - public final String encryptionIV; + public final @Nullable String encryptionIV; /** * The segment's byte range offset, as defined by #EXT-X-BYTERANGE. */ @@ -81,12 +84,24 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * @param byterangeLength See {@link #byterangeLength}. */ public Segment(String uri, long byterangeOffset, long byterangeLength) { - this(uri, null, 0, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength, false); + this( + uri, + /* initializationSegment= */ null, + /* title= */ "", + /* durationUs= */ 0, + /* relativeDiscontinuitySequence= */ -1, + /* relativeStartTimeUs= */ C.TIME_UNSET, + /* fullSegmentEncryptionKeyUri= */ null, + /* encryptionIV= */ null, + byterangeOffset, + byterangeLength, + /* hasGapTag= */ false); } /** * @param url See {@link #url}. * @param initializationSegment See {@link #initializationSegment}. + * @param title See {@link #title}. * @param durationUs See {@link #durationUs}. * @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}. * @param relativeStartTimeUs See {@link #relativeStartTimeUs}. @@ -98,17 +113,19 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ public Segment( String url, - Segment initializationSegment, + @Nullable Segment initializationSegment, + String title, long durationUs, int relativeDiscontinuitySequence, long relativeStartTimeUs, - String fullSegmentEncryptionKeyUri, - String encryptionIV, + @Nullable String fullSegmentEncryptionKeyUri, + @Nullable String encryptionIV, long byterangeOffset, long byterangeLength, boolean hasGapTag) { this.url = url; this.initializationSegment = initializationSegment; + this.title = title; this.durationUs = durationUs; this.relativeDiscontinuitySequence = relativeDiscontinuitySequence; this.relativeStartTimeUs = relativeStartTimeUs; @@ -173,10 +190,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * The target duration in microseconds, as defined by #EXT-X-TARGETDURATION. */ public final long targetDurationUs; - /** - * Whether the playlist contains the #EXT-X-INDEPENDENT-SEGMENTS tag. - */ - public final boolean hasIndependentSegmentsTag; /** * Whether the playlist contains the #EXT-X-ENDLIST tag. */ @@ -210,7 +223,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * @param mediaSequence See {@link #mediaSequence}. * @param version See {@link #version}. * @param targetDurationUs See {@link #targetDurationUs}. - * @param hasIndependentSegmentsTag See {@link #hasIndependentSegmentsTag}. + * @param hasIndependentSegments See {@link #hasIndependentSegments}. * @param hasEndTag See {@link #hasEndTag}. * @param hasProgramDateTime See {@link #hasProgramDateTime}. * @param drmInitData See {@link #drmInitData}. @@ -227,12 +240,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist { long mediaSequence, int version, long targetDurationUs, - boolean hasIndependentSegmentsTag, + boolean hasIndependentSegments, boolean hasEndTag, boolean hasProgramDateTime, DrmInitData drmInitData, List segments) { - super(baseUri, tags); + super(baseUri, tags, hasIndependentSegments); this.playlistType = playlistType; this.startTimeUs = startTimeUs; this.hasDiscontinuitySequence = hasDiscontinuitySequence; @@ -240,7 +253,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { this.mediaSequence = mediaSequence; this.version = version; this.targetDurationUs = targetDurationUs; - this.hasIndependentSegmentsTag = hasIndependentSegmentsTag; this.hasEndTag = hasEndTag; this.hasProgramDateTime = hasProgramDateTime; this.drmInitData = drmInitData; @@ -256,7 +268,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } @Override - public HlsMediaPlaylist copy(List renditionKeys) { + public HlsMediaPlaylist copy(List streamKeys) { return this; } @@ -294,7 +306,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * * @param startTimeUs The start time for the returned playlist. * @param discontinuitySequence The discontinuity sequence for the returned playlist. - * @return The playlist. + * @return An identical playlist including the provided discontinuity and timing information. */ public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) { return new HlsMediaPlaylist( @@ -308,7 +320,41 @@ public final class HlsMediaPlaylist extends HlsPlaylist { mediaSequence, version, targetDurationUs, - hasIndependentSegmentsTag, + hasIndependentSegments, + hasEndTag, + hasProgramDateTime, + drmInitData, + segments); + } + + /** + * Returns a playlist identical to this one, except for adding any inheritable attributes from the + * provided {@link HlsMasterPlaylist}. + * + *

    The inheritable attributes are: + * + *

      + *
    • {@link #hasIndependentSegments}. + *
    + * + * @return An identical playlist including the inheritable attributes from {@code masterPlaylist}. + */ + public HlsMediaPlaylist copyWithMasterPlaylistInfo(HlsMasterPlaylist masterPlaylist) { + if (hasIndependentSegments || !masterPlaylist.hasIndependentSegments) { + return this; + } + return new HlsMediaPlaylist( + playlistType, + baseUri, + tags, + startOffsetUs, + startTimeUs, + hasDiscontinuitySequence, + discontinuitySequence, + mediaSequence, + version, + targetDurationUs, + hasIndependentSegments || masterPlaylist.hasIndependentSegments, hasEndTag, hasProgramDateTime, drmInitData, @@ -318,8 +364,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { /** * Returns a playlist identical to this one except that an end tag is added. If an end tag is * already present then the playlist will return itself. - * - * @return The playlist. */ public HlsMediaPlaylist copyWithEndTag() { if (this.hasEndTag) { @@ -336,7 +380,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { mediaSequence, version, targetDurationUs, - hasIndependentSegmentsTag, + hasIndependentSegments, /* hasEndTag= */ true, hasProgramDateTime, drmInitData, diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistSegmentIterator.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistSegmentIterator.java new file mode 100755 index 000000000..4c654dc57 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistSegmentIterator.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.hls.playlist; + +import android.net.Uri; +import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; +import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.UriUtil; + +/** {@link MediaChunkIterator} wrapping a {@link HlsMediaPlaylist}. */ +public final class HlsMediaPlaylistSegmentIterator extends BaseMediaChunkIterator { + + private final HlsMediaPlaylist playlist; + private final long startOfPlaylistInPeriodUs; + + /** + * Creates iterator. + * + * @param playlist The {@link HlsMediaPlaylist} to wrap. + * @param startOfPlaylistInPeriodUs The start time of the playlist in the period, in microseconds. + * @param chunkIndex The chunk index in the playlist at which the iterator will start. + */ + public HlsMediaPlaylistSegmentIterator( + HlsMediaPlaylist playlist, long startOfPlaylistInPeriodUs, int chunkIndex) { + super(/* fromIndex= */ chunkIndex, /* toIndex= */ playlist.segments.size() - 1); + this.playlist = playlist; + this.startOfPlaylistInPeriodUs = startOfPlaylistInPeriodUs; + } + + @Override + public DataSpec getDataSpec() { + checkInBounds(); + HlsMediaPlaylist.Segment segment = playlist.segments.get((int) getCurrentIndex()); + Uri chunkUri = UriUtil.resolveToUri(playlist.baseUri, segment.url); + return new DataSpec( + chunkUri, segment.byterangeOffset, segment.byterangeLength, /* key= */ null); + } + + @Override + public long getChunkStartTimeUs() { + checkInBounds(); + HlsMediaPlaylist.Segment segment = playlist.segments.get((int) getCurrentIndex()); + return startOfPlaylistInPeriodUs + segment.relativeStartTimeUs; + } + + @Override + public long getChunkEndTimeUs() { + checkInBounds(); + HlsMediaPlaylist.Segment segment = playlist.segments.get((int) getCurrentIndex()); + long segmentStartTimeInPeriodUs = startOfPlaylistInPeriodUs + segment.relativeStartTimeUs; + return segmentStartTimeInPeriodUs + segment.durationUs; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylist.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java similarity index 67% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylist.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java index dc350cc48..9cec1cd33 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylist.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.playlist; +package com.google.android.exoplayer2.source.hls.playlist; -import org.telegram.messenger.exoplayer2.offline.FilterableManifest; +import com.google.android.exoplayer2.offline.FilterableManifest; import java.util.Collections; import java.util.List; /** Represents an HLS playlist. */ -public abstract class HlsPlaylist implements FilterableManifest { +public abstract class HlsPlaylist implements FilterableManifest { /** * The base uri. Used to resolve relative paths. @@ -30,14 +30,21 @@ public abstract class HlsPlaylist implements FilterableManifest tags; + /** + * Whether the media is formed of independent segments, as defined by the + * #EXT-X-INDEPENDENT-SEGMENTS tag. + */ + public final boolean hasIndependentSegments; /** * @param baseUri See {@link #baseUri}. * @param tags See {@link #tags}. + * @param hasIndependentSegments See {@link #hasIndependentSegments}. */ - protected HlsPlaylist(String baseUri, List tags) { + protected HlsPlaylist(String baseUri, List tags, boolean hasIndependentSegments) { this.baseUri = baseUri; this.tags = Collections.unmodifiableList(tags); + this.hasIndependentSegments = hasIndependentSegments; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 597f5a861..768583183 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.hls.playlist; +package com.google.android.exoplayer2.source.hls.playlist; import android.net.Uri; +import android.support.annotation.Nullable; import android.util.Base64; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.source.UnrecognizedInputFormatException; -import org.telegram.messenger.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.source.UnrecognizedInputFormatException; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -41,6 +42,7 @@ import java.util.List; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.checkerframework.checker.nullness.qual.PolyNull; /** * HLS playlists parsing logic. @@ -106,6 +108,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser muxedCaptionFormats = null; boolean noClosedCaptions = false; + boolean hasIndependentSegmentsTag = false; String line; while (iterator.hasNext()) { @@ -227,7 +232,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser(); } - muxedCaptionFormats.add(Format.createTextContainerFormat(id, null, mimeType, null, - Format.NO_VALUE, selectionFlags, language, accessibilityChannel)); + muxedCaptionFormats.add( + Format.createTextContainerFormat( + /* id= */ name, + /* label= */ name, + /* containerMimeType= */ null, + /* sampleMimeType= */ mimeType, + /* codecs= */ null, + /* bitrate= */ Format.NO_VALUE, + selectionFlags, + language, + accessibilityChannel)); break; default: // Do nothing. @@ -326,15 +371,30 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser tags = new ArrayList<>(); long segmentDurationUs = 0; + String segmentTitle = ""; boolean hasDiscontinuitySequence = false; int playlistDiscontinuitySequence = 0; int relativeDiscontinuitySequence = 0; @@ -406,6 +467,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.ParserThe playlist tracker is responsible for exposing the seeking window, which is defined by the + * segments that one of the playlists exposes. This playlist is called primary and needs to be + * periodically refreshed in the case of live streams. Note that the primary playlist is one of the + * media playlists while the master playlist is an optional kind of playlist defined by the HLS + * specification (RFC 8216). + * + *

    Playlist loads might encounter errors. The tracker may choose to blacklist them to ensure a + * primary playlist is always available. + */ +public interface HlsPlaylistTracker { + + /** Listener for primary playlist changes. */ + interface PrimaryPlaylistListener { + + /** + * Called when the primary playlist changes. + * + * @param mediaPlaylist The primary playlist new snapshot. + */ + void onPrimaryPlaylistRefreshed(HlsMediaPlaylist mediaPlaylist); + } + + /** Called on playlist loading events. */ + interface PlaylistEventListener { + + /** + * Called a playlist changes. + */ + void onPlaylistChanged(); + + /** + * Called if an error is encountered while loading a playlist. + * + * @param url The loaded url that caused the error. + * @param shouldBlacklist Whether the playlist should be blacklisted. + * @return True if blacklisting did not encounter errors. False otherwise. + */ + boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist); + } + + /** Thrown when a playlist is considered to be stuck due to a server side error. */ + final class PlaylistStuckException extends IOException { + + /** The url of the stuck playlist. */ + public final String url; + + /** + * Creates an instance. + * + * @param url See {@link #url}. + */ + public PlaylistStuckException(String url) { + this.url = url; + } + } + + /** Thrown when the media sequence of a new snapshot indicates the server has reset. */ + final class PlaylistResetException extends IOException { + + /** The url of the reset playlist. */ + public final String url; + + /** + * Creates an instance. + * + * @param url See {@link #url}. + */ + public PlaylistResetException(String url) { + this.url = url; + } + } + + /** + * Starts the playlist tracker. + * + *

    Must be called from the playback thread. A tracker may be restarted after a {@link #stop()} + * call. + * + * @param initialPlaylistUri Uri of the HLS stream. Can point to a media playlist or a master + * playlist. + * @param eventDispatcher A dispatcher to notify of events. + * @param listener A callback for the primary playlist change events. + */ + void start( + Uri initialPlaylistUri, EventDispatcher eventDispatcher, PrimaryPlaylistListener listener); + + /** + * Stops the playlist tracker and releases any acquired resources. + * + *

    Must be called once per {@link #start} call. + */ + void stop(); + + /** + * Registers a listener to receive events from the playlist tracker. + * + * @param listener The listener. + */ + void addListener(PlaylistEventListener listener); + + /** + * Unregisters a listener. + * + * @param listener The listener to unregister. + */ + void removeListener(PlaylistEventListener listener); + + /** + * Returns the master playlist. + * + *

    If the uri passed to {@link #start} points to a media playlist, an {@link HlsMasterPlaylist} + * with a single variant for said media playlist is returned. + * + * @return The master playlist. Null if the initial playlist has yet to be loaded. + */ + @Nullable + HlsMasterPlaylist getMasterPlaylist(); + + /** + * Returns the most recent snapshot available of the playlist referenced by the provided {@link + * HlsUrl}. + * + * @param url The {@link HlsUrl} corresponding to the requested media playlist. + * @return The most recent snapshot of the playlist referenced by the provided {@link HlsUrl}. May + * be null if no snapshot has been loaded yet. + */ + @Nullable + HlsMediaPlaylist getPlaylistSnapshot(HlsUrl url); + + /** + * Returns the start time of the first loaded primary playlist, or {@link C#TIME_UNSET} if no + * media playlist has been loaded. + */ + long getInitialStartTimeUs(); + + /** + * Returns whether the snapshot of the playlist referenced by the provided {@link HlsUrl} is + * valid, meaning all the segments referenced by the playlist are expected to be available. If the + * playlist is not valid then some of the segments may no longer be available. + * + * @param url The {@link HlsUrl}. + * @return Whether the snapshot of the playlist referenced by the provided {@link HlsUrl} is + * valid. + */ + boolean isSnapshotValid(HlsUrl url); + + /** + * If the tracker is having trouble refreshing the master playlist or the primary playlist, this + * method throws the underlying error. Otherwise, does nothing. + * + * @throws IOException The underlying error. + */ + void maybeThrowPrimaryPlaylistRefreshError() throws IOException; + + /** + * If the playlist is having trouble refreshing the playlist referenced by the given {@link + * HlsUrl}, this method throws the underlying error. + * + * @param url The {@link HlsUrl}. + * @throws IOException The underyling error. + */ + void maybeThrowPlaylistRefreshError(HlsUrl url) throws IOException; + + /** + * Requests a playlist refresh and whitelists it. + * + *

    The playlist tracker may choose the delay the playlist refresh. The request is discarded if + * a refresh was already pending. + * + * @param url The {@link HlsUrl} of the playlist to be refreshed. + */ + void refreshPlaylist(HlsUrl url); + + /** + * Returns whether the tracked playlists describe a live stream. + * + * @return True if the content is live. False otherwise. + */ + boolean isLive(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java index 8ced694da..aa20c12cf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java @@ -13,29 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming; +package com.google.android.exoplayer2.source.smoothstreaming; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import org.telegram.messenger.exoplayer2.extractor.mp4.Track; -import org.telegram.messenger.exoplayer2.extractor.mp4.TrackEncryptionBox; -import org.telegram.messenger.exoplayer2.source.BehindLiveWindowException; -import org.telegram.messenger.exoplayer2.source.chunk.Chunk; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkExtractorWrapper; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkHolder; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; -import org.telegram.messenger.exoplayer2.source.chunk.ContainerMediaChunk; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.mp4.Track; +import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; +import com.google.android.exoplayer2.source.BehindLiveWindowException; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.ChunkHolder; +import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; +import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.List; @@ -53,10 +55,17 @@ public class DefaultSsChunkSource implements SsChunkSource { } @Override - public SsChunkSource createChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, - SsManifest manifest, int elementIndex, TrackSelection trackSelection, - TrackEncryptionBox[] trackEncryptionBoxes) { + public SsChunkSource createChunkSource( + LoaderErrorThrower manifestLoaderErrorThrower, + SsManifest manifest, + int elementIndex, + TrackSelection trackSelection, + TrackEncryptionBox[] trackEncryptionBoxes, + @Nullable TransferListener transferListener) { DataSource dataSource = dataSourceFactory.createDataSource(); + if (transferListener != null) { + dataSource.addTransferListener(transferListener); + } return new DefaultSsChunkSource(manifestLoaderErrorThrower, manifest, elementIndex, trackSelection, dataSource, trackEncryptionBoxes); } @@ -166,7 +175,10 @@ public class DefaultSsChunkSource implements SsChunkSource { } @Override - public final void getNextChunk(MediaChunk previous, long playbackPositionUs, long loadPositionUs, + public final void getNextChunk( + long playbackPositionUs, + long loadPositionUs, + List queue, ChunkHolder out) { if (fatalError != null) { return; @@ -180,10 +192,11 @@ public class DefaultSsChunkSource implements SsChunkSource { } int chunkIndex; - if (previous == null) { + if (queue.isEmpty()) { chunkIndex = streamElement.getChunkIndex(loadPositionUs); } else { - chunkIndex = (int) (previous.getNextChunkIndex() - currentManifestChunkOffset); + chunkIndex = + (int) (queue.get(queue.size() - 1).getNextChunkIndex() - currentManifestChunkOffset); if (chunkIndex < 0) { // This is before the first chunk in the current manifest. fatalError = new BehindLiveWindowException(); @@ -203,7 +216,7 @@ public class DefaultSsChunkSource implements SsChunkSource { long chunkStartTimeUs = streamElement.getStartTimeUs(chunkIndex); long chunkEndTimeUs = chunkStartTimeUs + streamElement.getChunkDurationUs(chunkIndex); - long chunkSeekTimeUs = previous == null ? loadPositionUs : C.TIME_UNSET; + long chunkSeekTimeUs = queue.isEmpty() ? loadPositionUs : C.TIME_UNSET; int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset; int trackSelectionIndex = trackSelection.getSelectedIndex(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsChunkSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsChunkSource.java similarity index 67% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsChunkSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsChunkSource.java index b8e36f0f2..f333a6f92 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsChunkSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsChunkSource.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming; +package com.google.android.exoplayer2.source.smoothstreaming; -import org.telegram.messenger.exoplayer2.extractor.mp4.TrackEncryptionBox; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkSource; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; +import com.google.android.exoplayer2.source.chunk.ChunkSource; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; /** * A {@link ChunkSource} for SmoothStreaming. @@ -37,6 +39,8 @@ public interface SsChunkSource extends ChunkSource { * @param streamElementIndex The index of the corresponding stream element in the manifest. * @param trackSelection The track selection. * @param trackEncryptionBoxes Track encryption boxes for the stream. + * @param transferListener The transfer listener which should be informed of any data transfers. + * May be null if no listener is available. * @return The created {@link SsChunkSource}. */ SsChunkSource createChunkSource( @@ -44,7 +48,8 @@ public interface SsChunkSource extends ChunkSource { SsManifest manifest, int streamElementIndex, TrackSelection trackSelection, - TrackEncryptionBox[] trackEncryptionBoxes); + TrackEncryptionBox[] trackEncryptionBoxes, + @Nullable TransferListener transferListener); } /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaPeriod.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 8f43b15a4..a1fe499c2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -13,25 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming; +package com.google.android.exoplayer2.source.smoothstreaming; +import android.support.annotation.Nullable; import android.util.Base64; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.extractor.mp4.TrackEncryptionBox; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SampleStream; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.chunk.ChunkSampleStream; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.chunk.ChunkSampleStream; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; import java.util.ArrayList; @@ -44,6 +46,7 @@ import java.util.ArrayList; private static final int INITIALIZATION_VECTOR_SIZE = 8; private final SsChunkSource.Factory chunkSourceFactory; + private final @Nullable TransferListener transferListener; private final LoaderErrorThrower manifestLoaderErrorThrower; private final int minLoadableRetryCount; private final EventDispatcher eventDispatcher; @@ -52,17 +55,23 @@ import java.util.ArrayList; private final TrackEncryptionBox[] trackEncryptionBoxes; private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; - private Callback callback; + private @Nullable Callback callback; private SsManifest manifest; private ChunkSampleStream[] sampleStreams; private SequenceableLoader compositeSequenceableLoader; private boolean notifiedReadingStarted; - public SsMediaPeriod(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, + public SsMediaPeriod( + SsManifest manifest, + SsChunkSource.Factory chunkSourceFactory, + @Nullable TransferListener transferListener, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, - int minLoadableRetryCount, EventDispatcher eventDispatcher, - LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) { + int minLoadableRetryCount, + EventDispatcher eventDispatcher, + LoaderErrorThrower manifestLoaderErrorThrower, + Allocator allocator) { this.chunkSourceFactory = chunkSourceFactory; + this.transferListener = transferListener; this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.minLoadableRetryCount = minLoadableRetryCount; this.eventDispatcher = eventDispatcher; @@ -98,6 +107,7 @@ import java.util.ArrayList; for (ChunkSampleStream sampleStream : sampleStreams) { sampleStream.release(); } + callback = null; eventDispatcher.mediaPeriodReleased(); } @@ -212,8 +222,14 @@ import java.util.ArrayList; private ChunkSampleStream buildSampleStream(TrackSelection selection, long positionUs) { int streamElementIndex = trackGroups.indexOf(selection.getTrackGroup()); - SsChunkSource chunkSource = chunkSourceFactory.createChunkSource(manifestLoaderErrorThrower, - manifest, streamElementIndex, selection, trackEncryptionBoxes); + SsChunkSource chunkSource = + chunkSourceFactory.createChunkSource( + manifestLoaderErrorThrower, + manifest, + streamElementIndex, + selection, + trackEncryptionBoxes, + transferListener); return new ChunkSampleStream<>( manifest.streamElements[streamElementIndex].type, null, diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 5bd231872..692ebd0e2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -13,37 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming; +package com.google.android.exoplayer2.source.smoothstreaming; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.source.BaseMediaSource; -import org.telegram.messenger.exoplayer2.source.CompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; -import org.telegram.messenger.exoplayer2.source.MediaPeriod; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.EventDispatcher; -import org.telegram.messenger.exoplayer2.source.SequenceableLoader; -import org.telegram.messenger.exoplayer2.source.SinglePeriodTimeline; -import org.telegram.messenger.exoplayer2.source.ads.AdsMediaSource; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsUtil; -import org.telegram.messenger.exoplayer2.upstream.Allocator; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.Loader; -import org.telegram.messenger.exoplayer2.upstream.LoaderErrorThrower; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.BaseMediaSource; +import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SequenceableLoader; +import com.google.android.exoplayer2.source.SinglePeriodTimeline; +import com.google.android.exoplayer2.source.ads.AdsMediaSource; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; +import com.google.android.exoplayer2.upstream.LoaderErrorThrower; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; @@ -68,6 +70,16 @@ public final class SsMediaSource extends BaseMediaSource private boolean isCreateCalled; private @Nullable Object tag; + /** + * Creates a new factory for {@link SsMediaSource}s. + * + * @param dataSourceFactory A factory for {@link DataSource} instances that will be used to load + * manifest and media data. + */ + public Factory(DataSource.Factory dataSourceFactory) { + this(new DefaultSsChunkSource.Factory(dataSourceFactory), dataSourceFactory); + } + /** * Creates a new factory for {@link SsMediaSource}s. * @@ -283,6 +295,7 @@ public final class SsMediaSource extends BaseMediaSource private DataSource manifestDataSource; private Loader manifestLoader; private LoaderErrorThrower manifestLoaderErrorThrower; + private @Nullable TransferListener mediaTransferListener; private long manifestLoadStartTimestamp; private SsManifest manifest; @@ -461,7 +474,11 @@ public final class SsMediaSource extends BaseMediaSource // MediaSource implementation. @Override - public void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { + public void prepareSourceInternal( + ExoPlayer player, + boolean isTopLevelSource, + @Nullable TransferListener mediaTransferListener) { + this.mediaTransferListener = mediaTransferListener; if (sideloadedManifest) { manifestLoaderErrorThrower = new LoaderErrorThrower.Dummy(); processManifest(); @@ -483,9 +500,16 @@ public final class SsMediaSource extends BaseMediaSource public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { Assertions.checkArgument(id.periodIndex == 0); EventDispatcher eventDispatcher = createEventDispatcher(id); - SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, - compositeSequenceableLoaderFactory, minLoadableRetryCount, eventDispatcher, - manifestLoaderErrorThrower, allocator); + SsMediaPeriod period = + new SsMediaPeriod( + manifest, + chunkSourceFactory, + mediaTransferListener, + compositeSequenceableLoaderFactory, + minLoadableRetryCount, + eventDispatcher, + manifestLoaderErrorThrower, + allocator); mediaPeriods.add(period); return period; } @@ -518,6 +542,7 @@ public final class SsMediaSource extends BaseMediaSource long loadDurationMs) { manifestEventDispatcher.loadCompleted( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -533,6 +558,7 @@ public final class SsMediaSource extends BaseMediaSource long loadDurationMs, boolean released) { manifestEventDispatcher.loadCanceled( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -540,14 +566,16 @@ public final class SsMediaSource extends BaseMediaSource } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, - IOException error) { + IOException error, + int errorCount) { boolean isFatal = error instanceof ParserException; manifestEventDispatcher.loadError( loadable.dataSpec, + loadable.getUri(), loadable.type, elapsedRealtimeMs, loadDurationMs, @@ -641,7 +669,8 @@ public final class SsMediaSource extends BaseMediaSource ParsingLoadable loadable = new ParsingLoadable<>(manifestDataSource, manifestUri, C.DATA_TYPE_MANIFEST, manifestParser); long elapsedRealtimeMs = manifestLoader.startLoading(loadable, this, minLoadableRetryCount); - manifestEventDispatcher.loadStarted(loadable.dataSpec, loadable.type, elapsedRealtimeMs); + manifestEventDispatcher.loadStarted( + loadable.dataSpec, loadable.dataSpec.uri, loadable.type, elapsedRealtimeMs); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifest.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifest.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java index b7b189571..51284f06c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifest.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java @@ -13,15 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest; +package com.google.android.exoplayer2.source.smoothstreaming.manifest; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.offline.FilterableManifest; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.UriUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.offline.FilterableManifest; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; +import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.UriUtil; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,125 +37,9 @@ import java.util.UUID; * @see IIS Smooth * Streaming Client Manifest Format */ -public class SsManifest implements FilterableManifest { +public class SsManifest implements FilterableManifest { - public static final int UNSET_LOOKAHEAD = -1; - - /** - * The client manifest major version. - */ - public final int majorVersion; - - /** - * The client manifest minor version. - */ - public final int minorVersion; - - /** - * The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if the lookahead is - * unspecified. - */ - public final int lookAheadCount; - - /** - * Whether the manifest describes a live presentation still in progress. - */ - public final boolean isLive; - - /** - * Content protection information, or null if the content is not protected. - */ - public final ProtectionElement protectionElement; - - /** - * The contained stream elements. - */ - public final StreamElement[] streamElements; - - /** - * The overall presentation duration of the media in microseconds, or {@link C#TIME_UNSET} - * if the duration is unknown. - */ - public final long durationUs; - - /** - * The length of the trailing window for a live broadcast in microseconds, or - * {@link C#TIME_UNSET} if the stream is not live or if the window length is unspecified. - */ - public final long dvrWindowLengthUs; - - /** - * @param majorVersion The client manifest major version. - * @param minorVersion The client manifest minor version. - * @param timescale The timescale of the media as the number of units that pass in one second. - * @param duration The overall presentation duration in units of the timescale attribute, or 0 - * if the duration is unknown. - * @param dvrWindowLength The length of the trailing window in units of the timescale attribute, - * or 0 if this attribute is unspecified or not applicable. - * @param lookAheadCount The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if - * this attribute is unspecified or not applicable. - * @param isLive True if the manifest describes a live presentation still in progress. False - * otherwise. - * @param protectionElement Content protection information, or null if the content is not - * protected. - * @param streamElements The contained stream elements. - */ - public SsManifest(int majorVersion, int minorVersion, long timescale, long duration, - long dvrWindowLength, int lookAheadCount, boolean isLive, ProtectionElement protectionElement, - StreamElement[] streamElements) { - this(majorVersion, minorVersion, - duration == 0 ? C.TIME_UNSET - : Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, timescale), - dvrWindowLength == 0 ? C.TIME_UNSET - : Util.scaleLargeTimestamp(dvrWindowLength, C.MICROS_PER_SECOND, timescale), - lookAheadCount, isLive, protectionElement, streamElements); - } - - private SsManifest(int majorVersion, int minorVersion, long durationUs, long dvrWindowLengthUs, - int lookAheadCount, boolean isLive, ProtectionElement protectionElement, - StreamElement[] streamElements) { - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; - this.durationUs = durationUs; - this.dvrWindowLengthUs = dvrWindowLengthUs; - this.lookAheadCount = lookAheadCount; - this.isLive = isLive; - this.protectionElement = protectionElement; - this.streamElements = streamElements; - } - - @Override - public final SsManifest copy(List streamKeys) { - ArrayList sortedKeys = new ArrayList<>(streamKeys); - Collections.sort(sortedKeys); - - StreamElement currentStreamElement = null; - List copiedStreamElements = new ArrayList<>(); - List copiedFormats = new ArrayList<>(); - for (int i = 0; i < sortedKeys.size(); i++) { - StreamKey key = sortedKeys.get(i); - StreamElement streamElement = streamElements[key.streamElementIndex]; - if (streamElement != currentStreamElement && currentStreamElement != null) { - // We're advancing to a new stream element. Add the current one. - copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0]))); - copiedFormats.clear(); - } - currentStreamElement = streamElement; - copiedFormats.add(streamElement.formats[key.trackIndex]); - } - if (currentStreamElement != null) { - // Add the last stream element. - copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0]))); - } - - StreamElement[] copiedStreamElementsArray = copiedStreamElements.toArray(new StreamElement[0]); - return new SsManifest(majorVersion, minorVersion, durationUs, dvrWindowLengthUs, lookAheadCount, - isLive, protectionElement, copiedStreamElementsArray); - } - - /** - * Represents a protection element containing a single header. - */ + /** Represents a protection element containing a single header. */ public static class ProtectionElement { public final UUID uuid; @@ -161,7 +49,45 @@ public class SsManifest implements FilterableManifest { this.uuid = uuid; this.data = data; } + } + /** {@link MediaChunkIterator} wrapping a track of a {@link StreamElement}. */ + public static final class StreamElementIterator extends BaseMediaChunkIterator { + + private final StreamElement streamElement; + private final int trackIndex; + + /** + * Creates iterator. + * + * @param streamElement The {@link StreamElement} to wrap. + * @param trackIndex The track index in the stream element. + * @param chunkIndex The chunk index at which the iterator will start. + */ + public StreamElementIterator(StreamElement streamElement, int trackIndex, int chunkIndex) { + super(/* fromIndex= */ chunkIndex, /* toIndex= */ streamElement.chunkCount - 1); + this.streamElement = streamElement; + this.trackIndex = trackIndex; + } + + @Override + public DataSpec getDataSpec() { + checkInBounds(); + Uri uri = streamElement.buildRequestUri(trackIndex, (int) getCurrentIndex()); + return new DataSpec(uri); + } + + @Override + public long getChunkStartTimeUs() { + checkInBounds(); + return streamElement.getStartTimeUs((int) getCurrentIndex()); + } + + @Override + public long getChunkEndTimeUs() { + long chunkStartTimeUs = getChunkStartTimeUs(); + return chunkStartTimeUs + streamElement.getChunkDurationUs((int) getCurrentIndex()); + } } /** @@ -301,7 +227,136 @@ public class SsManifest implements FilterableManifest { .replace(URL_PLACEHOLDER_START_TIME_2, startTimeString); return UriUtil.resolveToUri(baseUri, chunkUrl); } - } + public static final int UNSET_LOOKAHEAD = -1; + + /** The client manifest major version. */ + public final int majorVersion; + + /** The client manifest minor version. */ + public final int minorVersion; + + /** + * The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if the lookahead is + * unspecified. + */ + public final int lookAheadCount; + + /** Whether the manifest describes a live presentation still in progress. */ + public final boolean isLive; + + /** Content protection information, or null if the content is not protected. */ + public final ProtectionElement protectionElement; + + /** The contained stream elements. */ + public final StreamElement[] streamElements; + + /** + * The overall presentation duration of the media in microseconds, or {@link C#TIME_UNSET} if the + * duration is unknown. + */ + public final long durationUs; + + /** + * The length of the trailing window for a live broadcast in microseconds, or {@link C#TIME_UNSET} + * if the stream is not live or if the window length is unspecified. + */ + public final long dvrWindowLengthUs; + + /** + * @param majorVersion The client manifest major version. + * @param minorVersion The client manifest minor version. + * @param timescale The timescale of the media as the number of units that pass in one second. + * @param duration The overall presentation duration in units of the timescale attribute, or 0 if + * the duration is unknown. + * @param dvrWindowLength The length of the trailing window in units of the timescale attribute, + * or 0 if this attribute is unspecified or not applicable. + * @param lookAheadCount The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if + * this attribute is unspecified or not applicable. + * @param isLive True if the manifest describes a live presentation still in progress. False + * otherwise. + * @param protectionElement Content protection information, or null if the content is not + * protected. + * @param streamElements The contained stream elements. + */ + public SsManifest( + int majorVersion, + int minorVersion, + long timescale, + long duration, + long dvrWindowLength, + int lookAheadCount, + boolean isLive, + ProtectionElement protectionElement, + StreamElement[] streamElements) { + this( + majorVersion, + minorVersion, + duration == 0 + ? C.TIME_UNSET + : Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, timescale), + dvrWindowLength == 0 + ? C.TIME_UNSET + : Util.scaleLargeTimestamp(dvrWindowLength, C.MICROS_PER_SECOND, timescale), + lookAheadCount, + isLive, + protectionElement, + streamElements); + } + + private SsManifest( + int majorVersion, + int minorVersion, + long durationUs, + long dvrWindowLengthUs, + int lookAheadCount, + boolean isLive, + ProtectionElement protectionElement, + StreamElement[] streamElements) { + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.durationUs = durationUs; + this.dvrWindowLengthUs = dvrWindowLengthUs; + this.lookAheadCount = lookAheadCount; + this.isLive = isLive; + this.protectionElement = protectionElement; + this.streamElements = streamElements; + } + + @Override + public final SsManifest copy(List streamKeys) { + ArrayList sortedKeys = new ArrayList<>(streamKeys); + Collections.sort(sortedKeys); + + StreamElement currentStreamElement = null; + List copiedStreamElements = new ArrayList<>(); + List copiedFormats = new ArrayList<>(); + for (int i = 0; i < sortedKeys.size(); i++) { + StreamKey key = sortedKeys.get(i); + StreamElement streamElement = streamElements[key.groupIndex]; + if (streamElement != currentStreamElement && currentStreamElement != null) { + // We're advancing to a new stream element. Add the current one. + copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0]))); + copiedFormats.clear(); + } + currentStreamElement = streamElement; + copiedFormats.add(streamElement.formats[key.trackIndex]); + } + if (currentStreamElement != null) { + // Add the last stream element. + copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0]))); + } + + StreamElement[] copiedStreamElementsArray = copiedStreamElements.toArray(new StreamElement[0]); + return new SsManifest( + majorVersion, + minorVersion, + durationUs, + dvrWindowLengthUs, + lookAheadCount, + isLive, + protectionElement, + copiedStreamElementsArray); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java index 08f693a7e..c2437db18 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java @@ -13,25 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest; +package com.google.android.exoplayer2.source.smoothstreaming.manifest; import android.net.Uri; import android.text.TextUtils; import android.util.Base64; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; -import org.telegram.messenger.exoplayer2.extractor.mp4.PsshAtomUtil; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; +import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -603,6 +603,7 @@ public class SsManifestParser implements ParsingLoadable.Parser { private static final String KEY_FOUR_CC = "FourCC"; private static final String KEY_TYPE = "Type"; private static final String KEY_LANGUAGE = "Language"; + private static final String KEY_NAME = "Name"; private static final String KEY_MAX_WIDTH = "MaxWidth"; private static final String KEY_MAX_HEIGHT = "MaxHeight"; @@ -616,6 +617,7 @@ public class SsManifestParser implements ParsingLoadable.Parser { public void parseStartTag(XmlPullParser parser) throws ParserException { int type = (Integer) getNormalizedAttribute(KEY_TYPE); String id = parser.getAttributeValue(null, KEY_INDEX); + String name = (String) getNormalizedAttribute(KEY_NAME); int bitrate = parseRequiredInt(parser, KEY_BITRATE); String sampleMimeType = fourCCToMimeType(parseRequiredString(parser, KEY_FOUR_CC)); @@ -624,8 +626,19 @@ public class SsManifestParser implements ParsingLoadable.Parser { int height = parseRequiredInt(parser, KEY_MAX_HEIGHT); List codecSpecificData = buildCodecSpecificData( parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA)); - format = Format.createVideoContainerFormat(id, MimeTypes.VIDEO_MP4, sampleMimeType, null, - bitrate, width, height, Format.NO_VALUE, codecSpecificData, 0); + format = + Format.createVideoContainerFormat( + id, + name, + MimeTypes.VIDEO_MP4, + sampleMimeType, + /* codecs= */ null, + bitrate, + width, + height, + /* frameRate= */ Format.NO_VALUE, + codecSpecificData, + /* selectionFlags= */ 0); } else if (type == C.TRACK_TYPE_AUDIO) { sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType; int channels = parseRequiredInt(parser, KEY_CHANNELS); @@ -637,15 +650,42 @@ public class SsManifestParser implements ParsingLoadable.Parser { CodecSpecificDataUtil.buildAacLcAudioSpecificConfig(samplingRate, channels)); } String language = (String) getNormalizedAttribute(KEY_LANGUAGE); - format = Format.createAudioContainerFormat(id, MimeTypes.AUDIO_MP4, sampleMimeType, null, - bitrate, channels, samplingRate, codecSpecificData, 0, language); + format = + Format.createAudioContainerFormat( + id, + name, + MimeTypes.AUDIO_MP4, + sampleMimeType, + /* codecs= */ null, + bitrate, + channels, + samplingRate, + codecSpecificData, + /* selectionFlags= */ 0, + language); } else if (type == C.TRACK_TYPE_TEXT) { String language = (String) getNormalizedAttribute(KEY_LANGUAGE); - format = Format.createTextContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, - null, bitrate, 0, language); + format = + Format.createTextContainerFormat( + id, + name, + MimeTypes.APPLICATION_MP4, + sampleMimeType, + /* codecs= */ null, + bitrate, + /* selectionFlags= */ 0, + language); } else { - format = Format.createContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, null, - bitrate, 0, null); + format = + Format.createContainerFormat( + id, + name, + MimeTypes.APPLICATION_MP4, + sampleMimeType, + /* codecs= */ null, + bitrate, + /* selectionFlags= */ 0, + /* language= */ null); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsUtil.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsUtil.java index 67b9d62bb..4adf6acff 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/manifest/SsUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsUtil.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest; +package com.google.android.exoplayer2.source.smoothstreaming.manifest; import android.net.Uri; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; /** SmoothStreaming related utility methods. */ public final class SsUtil { diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java new file mode 100755 index 000000000..ad2196fd7 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.smoothstreaming.offline; + +import android.net.Uri; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.offline.DownloadAction; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloadAction; +import com.google.android.exoplayer2.offline.StreamKey; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** An action to download or remove downloaded SmoothStreaming streams. */ +public final class SsDownloadAction extends SegmentDownloadAction { + + private static final String TYPE = "ss"; + private static final int VERSION = 1; + + public static final Deserializer DESERIALIZER = + new SegmentDownloadActionDeserializer(TYPE, VERSION) { + + @Override + protected StreamKey readKey(int version, DataInputStream input) throws IOException { + if (version > 0) { + return super.readKey(version, input); + } + int groupIndex = input.readInt(); + int trackIndex = input.readInt(); + return new StreamKey(groupIndex, trackIndex); + } + + @Override + protected DownloadAction createDownloadAction( + Uri uri, boolean isRemoveAction, byte[] data, List keys) { + return new SsDownloadAction(uri, isRemoveAction, data, keys); + } + }; + + /** + * Creates a SmoothStreaming download action. + * + * @param uri The URI of the media to be downloaded. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + * @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded. + */ + public static SsDownloadAction createDownloadAction( + Uri uri, @Nullable byte[] data, List keys) { + return new SsDownloadAction(uri, /* isRemoveAction= */ false, data, keys); + } + + /** + * Creates a SmoothStreaming remove action. + * + * @param uri The URI of the media to be removed. + * @param data Optional custom data for this action. If {@code null} an empty array will be used. + */ + public static SsDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) { + return new SsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + } + + /** + * @param uri The SmoothStreaming manifest URI. + * @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded. + * @param data Optional custom data for this action. + * @param keys Keys of streams to be downloaded. If empty, all streams are downloaded. If {@code + * removeAction} is true, {@code keys} must be empty. + * @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link + * #createRemoveAction(Uri, byte[])}. + */ + @Deprecated + public SsDownloadAction( + Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { + super(TYPE, VERSION, uri, isRemoveAction, data, keys); + } + + @Override + public SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { + return new SsDownloader(uri, keys, constructorHelper); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java similarity index 71% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java index b54026504..5125beff1 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadHelper.java @@ -13,24 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.offline; +package com.google.android.exoplayer2.source.smoothstreaming.offline; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.offline.DownloadHelper; -import org.telegram.messenger.exoplayer2.offline.TrackKey; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.StreamKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.offline.DownloadHelper; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.offline.TrackKey; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** A {@link DownloadHelper} for SmoothStreaming streams. */ public final class SsDownloadHelper extends DownloadHelper { @@ -38,7 +39,7 @@ public final class SsDownloadHelper extends DownloadHelper { private final Uri uri; private final DataSource.Factory manifestDataSourceFactory; - private SsManifest manifest; + private @MonotonicNonNull SsManifest manifest; public SsDownloadHelper(Uri uri, DataSource.Factory manifestDataSourceFactory) { this.uri = uri; @@ -48,7 +49,7 @@ public final class SsDownloadHelper extends DownloadHelper { @Override protected void prepareInternal() throws IOException { DataSource dataSource = manifestDataSourceFactory.createDataSource(); - manifest = ParsingLoadable.load(dataSource, new SsManifestParser(), uri); + manifest = ParsingLoadable.load(dataSource, new SsManifestParser(), uri, C.DATA_TYPE_MANIFEST); } /** Returns the SmoothStreaming manifest. Must not be called until after preparation completes. */ @@ -76,13 +77,12 @@ public final class SsDownloadHelper extends DownloadHelper { @Override public SsDownloadAction getDownloadAction(@Nullable byte[] data, List trackKeys) { - return new SsDownloadAction(uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys)); + return SsDownloadAction.createDownloadAction(uri, data, toStreamKeys(trackKeys)); } @Override public SsDownloadAction getRemoveAction(@Nullable byte[] data) { - return new SsDownloadAction( - uri, /* isRemoveAction= */ true, data, Collections.emptyList()); + return SsDownloadAction.createRemoveAction(uri, data); } private static List toStreamKeys(List trackKeys) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java similarity index 72% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java index c6211e2e6..84ef251e5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.offline; +package com.google.android.exoplayer2.source.smoothstreaming.offline; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloader; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.SsUtil; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.StreamKey; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.ParsingLoadable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; +import com.google.android.exoplayer2.offline.SegmentDownloader; +import com.google.android.exoplayer2.offline.StreamKey; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; +import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.ParsingLoadable; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -54,7 +54,7 @@ import java.util.List; * new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE); * } */ -public final class SsDownloader extends SegmentDownloader { +public final class SsDownloader extends SegmentDownloader { /** * @param manifestUri The {@link Uri} of the manifest to be downloaded. @@ -69,10 +69,7 @@ public final class SsDownloader extends SegmentDownloader @Override protected SsManifest getManifest(DataSource dataSource, Uri uri) throws IOException { - ParsingLoadable loadable = - new ParsingLoadable<>(dataSource, uri, C.DATA_TYPE_MANIFEST, new SsManifestParser()); - loadable.load(); - return loadable.getResult(); + return ParsingLoadable.load(dataSource, new SsManifestParser(), uri, C.DATA_TYPE_MANIFEST); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/CaptionStyleCompat.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/CaptionStyleCompat.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/CaptionStyleCompat.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/CaptionStyleCompat.java index dec95262b..51f5ad0a6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/CaptionStyleCompat.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/CaptionStyleCompat.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; import android.annotation.TargetApi; import android.graphics.Color; @@ -21,7 +21,7 @@ import android.graphics.Typeface; import android.support.annotation.IntDef; import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager.CaptionStyle; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Cue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Cue.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Cue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Cue.java index 1d5b5c447..8bc0b8e13 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Cue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Cue.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; import android.graphics.Bitmap; import android.graphics.Color; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleDecoder.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleDecoder.java index 456eef121..997f750b6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleDecoder.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.decoder.SimpleDecoder; import java.nio.ByteBuffer; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleOutputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleOutputBuffer.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleOutputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleOutputBuffer.java index 82ddc7edf..b2c25631f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SimpleSubtitleOutputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SimpleSubtitleOutputBuffer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; /** * A {@link SubtitleOutputBuffer} for decoders that extend {@link SimpleSubtitleDecoder}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Subtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Subtitle.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Subtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Subtitle.java index 2dbf98f10..4dc5f61fb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/Subtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/Subtitle.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.util.List; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoder.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoder.java index deac44763..2b080c656 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoder.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.decoder.Decoder; +import com.google.android.exoplayer2.decoder.Decoder; /** * Decodes {@link Subtitle}s from {@link SubtitleInputBuffer}s. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderException.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderException.java index 0fd722d2d..b0e9c2d3c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; /** * Thrown when an error occurs decoding subtitle data. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index 8673786f8..a64a1835d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleDecoderFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.text.cea.Cea608Decoder; -import org.telegram.messenger.exoplayer2.text.cea.Cea708Decoder; -import org.telegram.messenger.exoplayer2.text.dvb.DvbDecoder; -import org.telegram.messenger.exoplayer2.text.pgs.PgsDecoder; -import org.telegram.messenger.exoplayer2.text.ssa.SsaDecoder; -import org.telegram.messenger.exoplayer2.text.subrip.SubripDecoder; -import org.telegram.messenger.exoplayer2.text.ttml.TtmlDecoder; -import org.telegram.messenger.exoplayer2.text.tx3g.Tx3gDecoder; -import org.telegram.messenger.exoplayer2.text.webvtt.Mp4WebvttDecoder; -import org.telegram.messenger.exoplayer2.text.webvtt.WebvttDecoder; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.text.cea.Cea608Decoder; +import com.google.android.exoplayer2.text.cea.Cea708Decoder; +import com.google.android.exoplayer2.text.dvb.DvbDecoder; +import com.google.android.exoplayer2.text.pgs.PgsDecoder; +import com.google.android.exoplayer2.text.ssa.SsaDecoder; +import com.google.android.exoplayer2.text.subrip.SubripDecoder; +import com.google.android.exoplayer2.text.ttml.TtmlDecoder; +import com.google.android.exoplayer2.text.tx3g.Tx3gDecoder; +import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; +import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; +import com.google.android.exoplayer2.util.MimeTypes; /** * A factory for {@link SubtitleDecoder} instances. @@ -107,7 +107,7 @@ public interface SubtitleDecoderFactory { case MimeTypes.APPLICATION_MP4CEA608: return new Cea608Decoder(format.sampleMimeType, format.accessibilityChannel); case MimeTypes.APPLICATION_CEA708: - return new Cea708Decoder(format.accessibilityChannel); + return new Cea708Decoder(format.accessibilityChannel, format.initializationData); case MimeTypes.APPLICATION_DVBSUBS: return new DvbDecoder(format.initializationData); case MimeTypes.APPLICATION_PGS: diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleInputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleInputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java index 3247185a9..9866517a5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleInputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; /** A {@link DecoderInputBuffer} for a {@link SubtitleDecoder}. */ public class SubtitleInputBuffer extends DecoderInputBuffer { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleOutputBuffer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleOutputBuffer.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleOutputBuffer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleOutputBuffer.java index efbc0c298..75b7a0167 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/SubtitleOutputBuffer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/SubtitleOutputBuffer.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.decoder.OutputBuffer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.decoder.OutputBuffer; import java.util.List; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextOutput.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextOutput.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextOutput.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextOutput.java index 06e3f159e..5a08db94c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextOutput.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextOutput.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java index db0eeee10..5b74bd150 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/TextRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java @@ -13,20 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text; +package com.google.android.exoplayer2.text; import android.os.Handler; import android.os.Handler.Callback; import android.os.Looper; import android.os.Message; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.BaseRenderer; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.FormatHolder; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.BaseRenderer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; @@ -70,7 +72,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { private static final int MSG_UPDATE_OUTPUT = 0; - private final Handler outputHandler; + private final @Nullable Handler outputHandler; private final TextOutput output; private final SubtitleDecoderFactory decoderFactory; private final FormatHolder formatHolder; @@ -87,30 +89,31 @@ public final class TextRenderer extends BaseRenderer implements Callback { /** * @param output The output. - * @param outputLooper The looper associated with the thread on which the output should be - * called. If the output makes use of standard Android UI components, then this should - * normally be the looper associated with the application's main thread, which can be obtained - * using {@link android.app.Activity#getMainLooper()}. Null may be passed if the output - * should be called directly on the player's internal rendering thread. + * @param outputLooper The looper associated with the thread on which the output should be called. + * If the output makes use of standard Android UI components, then this should normally be the + * looper associated with the application's main thread, which can be obtained using {@link + * android.app.Activity#getMainLooper()}. Null may be passed if the output should be called + * directly on the player's internal rendering thread. */ - public TextRenderer(TextOutput output, Looper outputLooper) { + public TextRenderer(TextOutput output, @Nullable Looper outputLooper) { this(output, outputLooper, SubtitleDecoderFactory.DEFAULT); } /** * @param output The output. - * @param outputLooper The looper associated with the thread on which the output should be - * called. If the output makes use of standard Android UI components, then this should - * normally be the looper associated with the application's main thread, which can be obtained - * using {@link android.app.Activity#getMainLooper()}. Null may be passed if the output - * should be called directly on the player's internal rendering thread. + * @param outputLooper The looper associated with the thread on which the output should be called. + * If the output makes use of standard Android UI components, then this should normally be the + * looper associated with the application's main thread, which can be obtained using {@link + * android.app.Activity#getMainLooper()}. Null may be passed if the output should be called + * directly on the player's internal rendering thread. * @param decoderFactory A factory from which to obtain {@link SubtitleDecoder} instances. */ - public TextRenderer(TextOutput output, Looper outputLooper, - SubtitleDecoderFactory decoderFactory) { + public TextRenderer( + TextOutput output, @Nullable Looper outputLooper, SubtitleDecoderFactory decoderFactory) { super(C.TRACK_TYPE_TEXT); this.output = Assertions.checkNotNull(output); - this.outputHandler = outputLooper == null ? null : new Handler(outputLooper, this); + this.outputHandler = + outputLooper == null ? null : Util.createHandler(outputLooper, /* callback= */ this); this.decoderFactory = decoderFactory; formatHolder = new FormatHolder(); } @@ -305,7 +308,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { } private void clearOutput() { - updateOutput(Collections.emptyList()); + updateOutput(Collections.emptyList()); } @SuppressWarnings("unchecked") diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea608Decoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea608Decoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java index b53003c01..725321e53 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea608Decoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; import android.graphics.Color; import android.graphics.Typeface; @@ -21,17 +21,17 @@ import android.text.Layout.Alignment; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleInputBuffer; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.text.SubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleInputBuffer; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.List; @@ -55,15 +55,13 @@ public final class Cea608Decoder extends CeaDecoder { private static final int[] ROW_INDICES = new int[] {11, 1, 3, 12, 14, 5, 7, 9}; private static final int[] COLUMN_INDICES = new int[] {0, 4, 8, 12, 16, 20, 24, 28}; - private static final int[] COLORS = new int[] { - Color.WHITE, - Color.GREEN, - Color.BLUE, - Color.CYAN, - Color.RED, - Color.YELLOW, - Color.MAGENTA, - }; + + private static final int[] STYLE_COLORS = + new int[] { + Color.WHITE, Color.GREEN, Color.BLUE, Color.CYAN, Color.RED, Color.YELLOW, Color.MAGENTA + }; + private static final int STYLE_ITALICS = 0x07; + private static final int STYLE_UNCHANGED = 0x08; // The default number of rows to display in roll-up captions mode. private static final int DEFAULT_CAPTIONS_ROW_COUNT = 4; @@ -374,18 +372,13 @@ public final class Cea608Decoder extends CeaDecoder { private void handleMidrowCtrl(byte cc2) { // TODO: support the extended styles (i.e. backgrounds and transparencies) - // cc2 - 0|0|1|0|ATRBT|U - // ATRBT is the 3-byte encoded attribute, and U is the underline toggle - boolean isUnderlined = (cc2 & 0x01) == 0x01; - currentCueBuilder.setUnderline(isUnderlined); + // A midrow control code advances the cursor. + currentCueBuilder.append(' '); - int attribute = (cc2 >> 1) & 0x0F; - if (attribute == 0x07) { - currentCueBuilder.setMidrowStyle(new StyleSpan(Typeface.ITALIC), 2); - currentCueBuilder.setMidrowStyle(new ForegroundColorSpan(Color.WHITE), 1); - } else { - currentCueBuilder.setMidrowStyle(new ForegroundColorSpan(COLORS[attribute]), 1); - } + // cc2 - 0|0|1|0|STYLE|U + boolean underline = (cc2 & 0x01) == 0x01; + int style = (cc2 >> 1) & 0x07; + currentCueBuilder.setStyle(style, underline); } private void handlePreambleAddressCode(byte cc1, byte cc2) { @@ -411,22 +404,18 @@ public final class Cea608Decoder extends CeaDecoder { currentCueBuilder.setRow(row); } - if ((cc2 & 0x01) == 0x01) { - currentCueBuilder.setPreambleStyle(new UnderlineSpan()); - } - // cc2 - 0|1|N|0|STYLE|U // cc2 - 0|1|N|1|CURSR|U - int attribute = cc2 >> 1 & 0x0F; - if (attribute <= 0x07) { - if (attribute == 0x07) { - currentCueBuilder.setPreambleStyle(new StyleSpan(Typeface.ITALIC)); - currentCueBuilder.setPreambleStyle(new ForegroundColorSpan(Color.WHITE)); - } else { - currentCueBuilder.setPreambleStyle(new ForegroundColorSpan(COLORS[attribute])); - } - } else { - currentCueBuilder.setIndent(COLUMN_INDICES[attribute & 0x07]); + boolean isCursor = (cc2 & 0x10) == 0x10; + boolean underline = (cc2 & 0x01) == 0x01; + int cursorOrStyle = (cc2 >> 1) & 0x07; + + // We need to call setStyle even for the isCursor case, to update the underline bit. + // STYLE_UNCHANGED is used for this case. + currentCueBuilder.setStyle(isCursor ? STYLE_UNCHANGED : cursorOrStyle, underline); + + if (isCursor) { + currentCueBuilder.setIndent(COLUMN_INDICES[cursorOrStyle]); } } @@ -582,44 +571,37 @@ public final class Cea608Decoder extends CeaDecoder { private static class CueBuilder { - private static final int POSITION_UNSET = -1; - // 608 captions define a 15 row by 32 column screen grid. These constants convert from 608 // positions to normalized screen position. private static final int SCREEN_CHARWIDTH = 32; private static final int BASE_ROW = 15; - private final List preambleStyles; - private final List midrowStyles; + private final List cueStyles; private final List rolledUpCaptions; - private final SpannableStringBuilder captionStringBuilder; + private final StringBuilder captionStringBuilder; private int row; private int indent; private int tabOffset; private int captionMode; private int captionRowCount; - private int underlineStartPosition; public CueBuilder(int captionMode, int captionRowCount) { - preambleStyles = new ArrayList<>(); - midrowStyles = new ArrayList<>(); + cueStyles = new ArrayList<>(); rolledUpCaptions = new ArrayList<>(); - captionStringBuilder = new SpannableStringBuilder(); + captionStringBuilder = new StringBuilder(); reset(captionMode); setCaptionRowCount(captionRowCount); } public void reset(int captionMode) { this.captionMode = captionMode; - preambleStyles.clear(); - midrowStyles.clear(); + cueStyles.clear(); rolledUpCaptions.clear(); - captionStringBuilder.clear(); + captionStringBuilder.setLength(0); row = BASE_ROW; indent = 0; tabOffset = 0; - underlineStartPosition = POSITION_UNSET; } public void setCaptionRowCount(int captionRowCount) { @@ -627,7 +609,8 @@ public final class Cea608Decoder extends CeaDecoder { } public boolean isEmpty() { - return preambleStyles.isEmpty() && midrowStyles.isEmpty() && rolledUpCaptions.isEmpty() + return cueStyles.isEmpty() + && rolledUpCaptions.isEmpty() && captionStringBuilder.length() == 0; } @@ -635,6 +618,16 @@ public final class Cea608Decoder extends CeaDecoder { int length = captionStringBuilder.length(); if (length > 0) { captionStringBuilder.delete(length - 1, length); + // Decrement style start positions if necessary. + for (int i = cueStyles.size() - 1; i >= 0; i--) { + CueStyle style = cueStyles.get(i); + if (style.start == length) { + style.start--; + } else { + // All earlier cues must have style.start < length. + break; + } + } } } @@ -648,11 +641,8 @@ public final class Cea608Decoder extends CeaDecoder { public void rollUp() { rolledUpCaptions.add(buildSpannableString()); - captionStringBuilder.clear(); - preambleStyles.clear(); - midrowStyles.clear(); - underlineStartPosition = POSITION_UNSET; - + captionStringBuilder.setLength(0); + cueStyles.clear(); int numRows = Math.min(captionRowCount, row); while (rolledUpCaptions.size() >= numRows) { rolledUpCaptions.remove(0); @@ -667,23 +657,8 @@ public final class Cea608Decoder extends CeaDecoder { tabOffset = tabs; } - public void setPreambleStyle(CharacterStyle style) { - preambleStyles.add(style); - } - - public void setMidrowStyle(CharacterStyle style, int nextStyleIncrement) { - midrowStyles.add(new CueStyle(style, captionStringBuilder.length(), nextStyleIncrement)); - } - - public void setUnderline(boolean enabled) { - if (enabled) { - underlineStartPosition = captionStringBuilder.length(); - } else if (underlineStartPosition != POSITION_UNSET) { - // underline spans won't overlap, so it's safe to modify the builder directly with them - captionStringBuilder.setSpan(new UnderlineSpan(), underlineStartPosition, - captionStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - underlineStartPosition = POSITION_UNSET; - } + public void setStyle(int style, boolean underline) { + cueStyles.add(new CueStyle(style, underline, captionStringBuilder.length())); } public void append(char text) { @@ -691,31 +666,69 @@ public final class Cea608Decoder extends CeaDecoder { } public SpannableString buildSpannableString() { - int length = captionStringBuilder.length(); + SpannableStringBuilder builder = new SpannableStringBuilder(captionStringBuilder); + int length = builder.length(); - // preamble styles apply to the entire cue - for (int i = 0; i < preambleStyles.size(); i++) { - captionStringBuilder.setSpan(preambleStyles.get(i), 0, length, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + int underlineStartPosition = C.INDEX_UNSET; + int italicStartPosition = C.INDEX_UNSET; + int colorStartPosition = 0; + int color = Color.WHITE; + + boolean nextItalic = false; + int nextColor = Color.WHITE; + + for (int i = 0; i < cueStyles.size(); i++) { + CueStyle cueStyle = cueStyles.get(i); + boolean underline = cueStyle.underline; + int style = cueStyle.style; + if (style != STYLE_UNCHANGED) { + // If the style is a color then italic is cleared. + nextItalic = style == STYLE_ITALICS; + // If the style is italic then the color is left unchanged. + nextColor = style == STYLE_ITALICS ? nextColor : STYLE_COLORS[style]; + } + + int position = cueStyle.start; + int nextPosition = (i + 1) < cueStyles.size() ? cueStyles.get(i + 1).start : length; + if (position == nextPosition) { + // There are more cueStyles to process at the current position. + continue; + } + + // Process changes to underline up to the current position. + if (underlineStartPosition != C.INDEX_UNSET && !underline) { + setUnderlineSpan(builder, underlineStartPosition, position); + underlineStartPosition = C.INDEX_UNSET; + } else if (underlineStartPosition == C.INDEX_UNSET && underline) { + underlineStartPosition = position; + } + // Process changes to italic up to the current position. + if (italicStartPosition != C.INDEX_UNSET && !nextItalic) { + setItalicSpan(builder, italicStartPosition, position); + italicStartPosition = C.INDEX_UNSET; + } else if (italicStartPosition == C.INDEX_UNSET && nextItalic) { + italicStartPosition = position; + } + // Process changes to color up to the current position. + if (nextColor != color) { + setColorSpan(builder, colorStartPosition, position, color); + color = nextColor; + colorStartPosition = position; + } } - // midrow styles only apply to part of the cue, and after preamble styles - for (int i = 0; i < midrowStyles.size(); i++) { - CueStyle cueStyle = midrowStyles.get(i); - int end = (i < midrowStyles.size() - cueStyle.nextStyleIncrement) - ? midrowStyles.get(i + cueStyle.nextStyleIncrement).start - : length; - captionStringBuilder.setSpan(cueStyle.style, cueStyle.start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + // Add any final spans. + if (underlineStartPosition != C.INDEX_UNSET && underlineStartPosition != length) { + setUnderlineSpan(builder, underlineStartPosition, length); + } + if (italicStartPosition != C.INDEX_UNSET && italicStartPosition != length) { + setItalicSpan(builder, italicStartPosition, length); + } + if (colorStartPosition != length) { + setColorSpan(builder, colorStartPosition, length, color); } - // special case for midrow underlines that went to the end of the cue - if (underlineStartPosition != POSITION_UNSET) { - captionStringBuilder.setSpan(new UnderlineSpan(), underlineStartPosition, length, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - return new SpannableString(captionStringBuilder); + return new SpannableString(builder); } public Cue build() { @@ -785,16 +798,34 @@ public final class Cea608Decoder extends CeaDecoder { return captionStringBuilder.toString(); } + private static void setUnderlineSpan(SpannableStringBuilder builder, int start, int end) { + builder.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + private static void setItalicSpan(SpannableStringBuilder builder, int start, int end) { + builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + private static void setColorSpan( + SpannableStringBuilder builder, int start, int end, int color) { + if (color == Color.WHITE) { + // White is treated as the default color (i.e. no span is attached). + return; + } + builder.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + private static class CueStyle { - public final CharacterStyle style; - public final int start; - public final int nextStyleIncrement; + public final int style; + public final boolean underline; - public CueStyle(CharacterStyle style, int start, int nextStyleIncrement) { + public int start; + + public CueStyle(int style, boolean underline, int start) { this.style = style; + this.underline = underline; this.start = start; - this.nextStyleIncrement = nextStyleIncrement; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Cue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Cue.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Cue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Cue.java index 802bd6ab1..0a3f36fa8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Cue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Cue.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; import android.support.annotation.NonNull; import android.text.Layout.Alignment; -import org.telegram.messenger.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Cue; /** * A {@link Cue} for CEA-708. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Decoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Decoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java index 28af979d2..f21804b01 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/Cea708Decoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; import android.graphics.Color; import android.graphics.Typeface; @@ -26,19 +26,18 @@ import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Cue.AnchorType; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleInputBuffer; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Cue.AnchorType; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.text.SubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleInputBuffer; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; /** @@ -153,10 +152,10 @@ public final class Cea708Decoder extends CeaDecoder { private DtvCcPacket currentDtvCcPacket; private int currentWindow; - public Cea708Decoder(int accessibilityChannel) { + public Cea708Decoder(int accessibilityChannel, List initializationData) { ccData = new ParsableByteArray(); serviceBlockPacket = new ParsableBitArray(); - selectedServiceNumber = (accessibilityChannel == Format.NO_VALUE) ? 1 : accessibilityChannel; + selectedServiceNumber = accessibilityChannel == Format.NO_VALUE ? 1 : accessibilityChannel; cueBuilders = new CueBuilder[NUM_WINDOWS]; for (int i = 0; i < NUM_WINDOWS; i++) { @@ -196,7 +195,10 @@ public final class Cea708Decoder extends CeaDecoder { @Override protected void decode(SubtitleInputBuffer inputBuffer) { - ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit()); + // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe. + @SuppressWarnings("ByteBufferBackingArray") + byte[] inputBufferData = inputBuffer.data.array(); + ccData.reset(inputBufferData, inputBuffer.data.limit()); while (ccData.bytesLeft() >= 3) { int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07); @@ -741,7 +743,7 @@ public final class Cea708Decoder extends CeaDecoder { } } Collections.sort(displayCues); - return Collections.unmodifiableList(displayCues); + return Collections.unmodifiableList(displayCues); } private void resetCueBuilders() { @@ -879,7 +881,7 @@ public final class Cea708Decoder extends CeaDecoder { private int row; public CueBuilder() { - rolledUpCaptions = new LinkedList<>(); + rolledUpCaptions = new ArrayList<>(); captionStringBuilder = new SpannableStringBuilder(); reset(); } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708InitializationData.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708InitializationData.java new file mode 100755 index 000000000..10bed14ad --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/Cea708InitializationData.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.text.cea; + +import java.util.Collections; +import java.util.List; + +/** Initialization data for CEA-708 decoders. */ +public final class Cea708InitializationData { + + /** + * Whether the closed caption service is formatted for displays with 16:9 aspect ratio. If false, + * the closed caption service is formatted for 4:3 displays. + */ + public final boolean isWideAspectRatio; + + private Cea708InitializationData(List initializationData) { + isWideAspectRatio = initializationData.get(0)[0] != 0; + } + + /** + * Returns an object representation of CEA-708 initialization data + * + * @param initializationData Binary CEA-708 initialization data. + * @return The object representation. + */ + public static Cea708InitializationData fromData(List initializationData) { + return new Cea708InitializationData(initializationData); + } + + /** + * Builds binary CEA-708 initialization data. + * + * @param isWideAspectRatio Whether the closed caption service is formatted for displays with 16:9 + * aspect ratio. + * @return Binary CEA-708 initializaton data. + */ + public static List buildData(boolean isWideAspectRatio) { + return Collections.singletonList(new byte[] {(byte) (isWideAspectRatio ? 1 : 0)}); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java index 47bee3f1c..3efc16bdd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; import android.support.annotation.NonNull; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.text.SubtitleInputBuffer; -import org.telegram.messenger.exoplayer2.text.SubtitleOutputBuffer; -import org.telegram.messenger.exoplayer2.util.Assertions; -import java.util.LinkedList; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.text.SubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.text.SubtitleInputBuffer; +import com.google.android.exoplayer2.text.SubtitleOutputBuffer; +import com.google.android.exoplayer2.util.Assertions; +import java.util.ArrayDeque; import java.util.PriorityQueue; /** @@ -35,8 +35,8 @@ import java.util.PriorityQueue; private static final int NUM_INPUT_BUFFERS = 10; private static final int NUM_OUTPUT_BUFFERS = 2; - private final LinkedList availableInputBuffers; - private final LinkedList availableOutputBuffers; + private final ArrayDeque availableInputBuffers; + private final ArrayDeque availableOutputBuffers; private final PriorityQueue queuedInputBuffers; private CeaInputBuffer dequeuedInputBuffer; @@ -44,11 +44,11 @@ import java.util.PriorityQueue; private long queuedInputBufferCount; public CeaDecoder() { - availableInputBuffers = new LinkedList<>(); + availableInputBuffers = new ArrayDeque<>(); for (int i = 0; i < NUM_INPUT_BUFFERS; i++) { availableInputBuffers.add(new CeaInputBuffer()); } - availableOutputBuffers = new LinkedList<>(); + availableOutputBuffers = new ArrayDeque<>(); for (int i = 0; i < NUM_OUTPUT_BUFFERS; i++) { availableOutputBuffers.add(new CeaOutputBuffer()); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaSubtitle.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaSubtitle.java index 357cc12bb..738f251e2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaSubtitle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; import java.util.Collections; import java.util.List; @@ -54,7 +54,7 @@ import java.util.List; @Override public List getCues(long timeUs) { - return timeUs >= 0 ? cues : Collections.emptyList(); + return timeUs >= 0 ? cues : Collections.emptyList(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaUtil.java similarity index 64% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaUtil.java index 471e8f691..911feadb5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/cea/CeaUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/cea/CeaUtil.java @@ -13,26 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.cea; +package com.google.android.exoplayer2.text.cea; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.TrackOutput; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; /** Utility methods for handling CEA-608/708 messages. Defined in A/53 Part 4:2009. */ public final class CeaUtil { private static final String TAG = "CeaUtil"; + public static final int USER_DATA_IDENTIFIER_GA94 = Util.getIntegerCodeForString("GA94"); + public static final int USER_DATA_TYPE_CODE_MPEG_CC = 0x3; + private static final int PAYLOAD_TYPE_CC = 4; private static final int COUNTRY_CODE = 0xB5; private static final int PROVIDER_CODE_ATSC = 0x31; private static final int PROVIDER_CODE_DIRECTV = 0x2F; - private static final int USER_ID_GA94 = Util.getIntegerCodeForString("GA94"); - private static final int USER_ID_DTG1 = Util.getIntegerCodeForString("DTG1"); - private static final int USER_DATA_TYPE_CODE = 0x3; /** * Consumes the unescaped content of an SEI NAL unit, writing the content of any CEA-608 messages @@ -67,32 +67,52 @@ public final class CeaUtil { boolean messageIsSupportedCeaCaption = countryCode == COUNTRY_CODE && (providerCode == PROVIDER_CODE_ATSC || providerCode == PROVIDER_CODE_DIRECTV) - && userDataTypeCode == USER_DATA_TYPE_CODE; + && userDataTypeCode == USER_DATA_TYPE_CODE_MPEG_CC; if (providerCode == PROVIDER_CODE_ATSC) { - messageIsSupportedCeaCaption &= - userIdentifier == USER_ID_GA94 || userIdentifier == USER_ID_DTG1; + messageIsSupportedCeaCaption &= userIdentifier == USER_DATA_IDENTIFIER_GA94; } if (messageIsSupportedCeaCaption) { - // Ignore first three bits: reserved (1) + process_cc_data_flag (1) + zero_bit (1). - int ccCount = seiBuffer.readUnsignedByte() & 0x1F; - // Ignore em_data (1) - seiBuffer.skipBytes(1); - // Each data packet consists of 24 bits: marker bits (5) + cc_valid (1) + cc_type (2) - // + cc_data_1 (8) + cc_data_2 (8). - int sampleLength = ccCount * 3; - int sampleStartPosition = seiBuffer.getPosition(); - for (TrackOutput output : outputs) { - seiBuffer.setPosition(sampleStartPosition); - output.sampleData(seiBuffer, sampleLength); - output.sampleMetadata( - presentationTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleLength, 0, null); - } + consumeCcData(presentationTimeUs, seiBuffer, outputs); } } seiBuffer.setPosition(nextPayloadPosition); } } + /** + * Consumes caption data (cc_data), writing the content as samples to all of the provided outputs. + * + * @param presentationTimeUs The presentation time in microseconds for any samples. + * @param ccDataBuffer The buffer containing the caption data. + * @param outputs The outputs to which any samples should be written. + */ + public static void consumeCcData( + long presentationTimeUs, ParsableByteArray ccDataBuffer, TrackOutput[] outputs) { + // First byte contains: reserved (1), process_cc_data_flag (1), zero_bit (1), cc_count (5). + int firstByte = ccDataBuffer.readUnsignedByte(); + boolean processCcDataFlag = (firstByte & 0x40) != 0; + if (!processCcDataFlag) { + // No need to process. + return; + } + int ccCount = firstByte & 0x1F; + ccDataBuffer.skipBytes(1); // Ignore em_data + // Each data packet consists of 24 bits: marker bits (5) + cc_valid (1) + cc_type (2) + // + cc_data_1 (8) + cc_data_2 (8). + int sampleLength = ccCount * 3; + int sampleStartPosition = ccDataBuffer.getPosition(); + for (TrackOutput output : outputs) { + ccDataBuffer.setPosition(sampleStartPosition); + output.sampleData(ccDataBuffer, sampleLength); + output.sampleMetadata( + presentationTimeUs, + C.BUFFER_FLAG_KEY_FRAME, + sampleLength, + /* offset= */ 0, + /* encryptionData= */ null); + } + } + /** * Reads a value from the provided buffer consisting of zero or more 0xFF bytes followed by a * terminating byte not equal to 0xFF. The returned value is ((0xFF * N) + T), where N is the diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbDecoder.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbDecoder.java index 755663c84..df5b19c05 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbDecoder.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.dvb; +package com.google.android.exoplayer2.text.dvb; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.List; /** A {@link SimpleSubtitleDecoder} for DVB subtitles. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java index 1b8a6e2a9..c0caf1e57 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.dvb; +package com.google.android.exoplayer2.text.dvb; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -24,9 +24,9 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Region; import android.util.Log; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.util.ParsableBitArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbSubtitle.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbSubtitle.java index e7f356c53..75728359c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/dvb/DvbSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/dvb/DvbSubtitle.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.dvb; +package com.google.android.exoplayer2.text.dvb; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; import java.util.List; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsDecoder.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsDecoder.java index 48883e4d5..1e4559514 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsDecoder.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.pgs; +package com.google.android.exoplayer2.text.pgs; import android.graphics.Bitmap; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsSubtitle.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsSubtitle.java index ce1b5c61d..9f9af6b6a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/pgs/PgsSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/pgs/PgsSubtitle.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.pgs; +package com.google.android.exoplayer2.text.pgs; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; import java.util.List; /** A representation of a PGS subtitle. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java index d6d95a8d9..e528a5776 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ssa; +package com.google.android.exoplayer2.text.ssa; import android.text.TextUtils; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.LongArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.LongArray; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -62,7 +62,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { super("SsaDecoder"); if (initializationData != null && !initializationData.isEmpty()) { haveInitializationData = true; - String formatLine = new String(initializationData.get(0)); + String formatLine = Util.fromUtf8Bytes(initializationData.get(0)); Assertions.checkArgument(formatLine.startsWith(FORMAT_LINE_PREFIX)); parseFormatLine(formatLine); parseHeader(new ParsableByteArray(initializationData.get(1))); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaSubtitle.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaSubtitle.java index db7f7c604..339119ed6 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ssa/SsaSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ssa/SsaSubtitle.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ssa; +package com.google.android.exoplayer2.text.ssa; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java index ce99145e6..6cce902e8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.subrip; +package com.google.android.exoplayer2.text.subrip; import android.text.Html; import android.text.Spanned; import android.text.TextUtils; import android.util.Log; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.util.LongArray; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.util.LongArray; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripSubtitle.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripSubtitle.java index b43a28f0a..a79df478e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/subrip/SubripSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/subrip/SubripSubtitle.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.subrip; +package com.google.android.exoplayer2.text.subrip; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.Collections; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java index c2e89a9f4..61e008506 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; import android.text.Layout; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ColorParser; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.util.XmlPullParserUtil; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ColorParser; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.XmlPullParserUtil; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.ArrayDeque; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -109,13 +109,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes, 0, length); xmlParser.setInput(inputStream, null); TtmlSubtitle ttmlSubtitle = null; - LinkedList nodeStack = new LinkedList<>(); + ArrayDeque nodeStack = new ArrayDeque<>(); int unsupportedNodeDepth = 0; int eventType = xmlParser.getEventType(); FrameAndTickRate frameAndTickRate = DEFAULT_FRAME_AND_TICK_RATE; CellResolution cellResolution = DEFAULT_CELL_RESOLUTION; while (eventType != XmlPullParser.END_DOCUMENT) { - TtmlNode parent = nodeStack.peekLast(); + TtmlNode parent = nodeStack.peek(); if (unsupportedNodeDepth == 0) { String name = xmlParser.getName(); if (eventType == XmlPullParser.START_TAG) { @@ -131,7 +131,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { } else { try { TtmlNode node = parseNode(xmlParser, parent, regionMap, frameAndTickRate); - nodeStack.addLast(node); + nodeStack.push(node); if (parent != null) { parent.addChild(node); } @@ -145,9 +145,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { parent.addChild(TtmlNode.buildTextNode(xmlParser.getText())); } else if (eventType == XmlPullParser.END_TAG) { if (xmlParser.getName().equals(TtmlNode.TAG_TT)) { - ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast(), globalStyles, regionMap); + ttmlSubtitle = new TtmlSubtitle(nodeStack.peek(), globalStyles, regionMap); } - nodeStack.removeLast(); + nodeStack.pop(); } } else { if (eventType == XmlPullParser.START_TAG) { @@ -178,7 +178,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { float frameRateMultiplier = 1; String frameRateMultiplierString = xmlParser.getAttributeValue(TTP, "frameRateMultiplier"); if (frameRateMultiplierString != null) { - String[] parts = frameRateMultiplierString.split(" "); + String[] parts = Util.split(frameRateMultiplierString, " "); if (parts.length != 2) { throw new SubtitleDecoderException("frameRateMultiplier doesn't have 2 parts"); } @@ -354,7 +354,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { } private String[] parseStyleIds(String parentStyleIds) { - return parentStyleIds.split("\\s+"); + parentStyleIds = parentStyleIds.trim(); + return parentStyleIds.isEmpty() ? new String[0] : Util.split(parentStyleIds, "\\s+"); } private TtmlStyle parseStyleAttributes(XmlPullParser parser, TtmlStyle style) { @@ -531,7 +532,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { private static void parseFontSize(String expression, TtmlStyle out) throws SubtitleDecoderException { - String[] expressions = expression.split("\\s+"); + String[] expressions = Util.split(expression, "\\s+"); Matcher matcher; if (expressions.length == 1) { matcher = FONT_SIZE.matcher(expression); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlNode.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlNode.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java index e87d10226..c8b9a59de 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlNode.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; import android.text.SpannableStringBuilder; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.util.Assertions; import java.util.ArrayList; import java.util.HashMap; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRegion.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRegion.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java index cb87c8e0f..2b1e9cf99 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRegion.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; -import org.telegram.messenger.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Cue; /** * Represents a TTML Region. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRenderUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRenderUtil.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRenderUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRenderUtil.java index e8fb81140..21333081c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlRenderUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRenderUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; import android.text.Spannable; import android.text.SpannableStringBuilder; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlStyle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlStyle.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlStyle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlStyle.java index 3c4e5ecf0..90f93d5b2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlStyle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlStyle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; import android.graphics.Typeface; import android.support.annotation.IntDef; import android.text.Layout; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java index a7e73c5e1..50916aa84 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/ttml/TtmlSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.ttml; +package com.google.android.exoplayer2.text.ttml; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Util; import java.util.Collections; import java.util.List; import java.util.Map; @@ -37,8 +37,8 @@ import java.util.Map; Map regionMap) { this.root = root; this.regionMap = regionMap; - this.globalStyles = globalStyles != null - ? Collections.unmodifiableMap(globalStyles) : Collections.emptyMap(); + this.globalStyles = + globalStyles != null ? Collections.unmodifiableMap(globalStyles) : Collections.emptyMap(); this.eventTimesUs = root.getEventTimesUs(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gDecoder.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gDecoder.java index eaa3fa1a1..ebc38bcd7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gDecoder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.tx3g; +package com.google.android.exoplayer2.text.tx3g; import android.graphics.Color; import android.graphics.Typeface; @@ -23,13 +23,13 @@ import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; import android.text.style.UnderlineSpan; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.nio.charset.Charset; import java.util.List; @@ -92,7 +92,8 @@ public final class Tx3gDecoder extends SimpleSubtitleDecoder { | ((initializationBytes[27] & 0xFF) << 16) | ((initializationBytes[28] & 0xFF) << 8) | (initializationBytes[29] & 0xFF); - String fontFamily = new String(initializationBytes, 43, initializationBytes.length - 43); + String fontFamily = + Util.fromUtf8Bytes(initializationBytes, 43, initializationBytes.length - 43); defaultFontFamily = TX3G_SERIF.equals(fontFamily) ? C.SERIF_NAME : C.SANS_SERIF_NAME; //font size (initializationBytes[25]) is 5% of video height calculatedVideoTrackHeight = 20 * initializationBytes[25]; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gSubtitle.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gSubtitle.java index 542290136..adb1190ce 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/tx3g/Tx3gSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/tx3g/Tx3gSubtitle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.tx3g; +package com.google.android.exoplayer2.text.tx3g; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; import java.util.Collections; import java.util.List; @@ -57,7 +57,7 @@ import java.util.List; @Override public List getCues(long timeUs) { - return timeUs >= 0 ? cues : Collections.emptyList(); + return timeUs >= 0 ? cues : Collections.emptyList(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/CssParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/CssParser.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/CssParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/CssParser.java index 9fad3c8e3..81c362bda 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/CssParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/CssParser.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.util.ColorParser; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.ColorParser; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -314,7 +315,7 @@ import java.util.regex.Pattern; } selector = selector.substring(0, voiceStartIndex); } - String[] classDivision = selector.split("\\."); + String[] classDivision = Util.split(selector, "\\."); String tagAndIdDivision = classDivision[0]; int idPrefixIndex = tagAndIdDivision.indexOf('#'); if (idPrefixIndex != -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttDecoder.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttDecoder.java index dc2ccc8cc..8cb0ac58c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttDecoder.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -78,14 +78,14 @@ public final class Mp4WebvttDecoder extends SimpleSubtitleDecoder { int boxType = sampleData.readInt(); remainingCueBoxBytes -= BOX_HEADER_SIZE; int payloadLength = boxSize - BOX_HEADER_SIZE; - String boxPayload = new String(sampleData.data, sampleData.getPosition(), payloadLength); + String boxPayload = + Util.fromUtf8Bytes(sampleData.data, sampleData.getPosition(), payloadLength); sampleData.skipBytes(payloadLength); remainingCueBoxBytes -= payloadLength; if (boxType == TYPE_sttg) { WebvttCueParser.parseCueSettingsList(boxPayload, builder); } else if (boxType == TYPE_payl) { - WebvttCueParser.parseCueText(null, boxPayload.trim(), builder, - Collections.emptyList()); + WebvttCueParser.parseCueText(null, boxPayload.trim(), builder, Collections.emptyList()); } else { // Other VTTCueBox children are still not supported and are ignored. } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java index 9cbb51ca6..c87c88133 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/Mp4WebvttSubtitle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; import java.util.Collections; import java.util.List; @@ -51,6 +51,6 @@ import java.util.List; @Override public List getCues(long timeUs) { - return timeUs >= 0 ? cues : Collections.emptyList(); + return timeUs >= 0 ? cues : Collections.emptyList(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCssStyle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCssStyle.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCssStyle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCssStyle.java index a931fa8e2..a78c5afa7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCssStyle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCssStyle.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.graphics.Typeface; import android.support.annotation.IntDef; import android.text.Layout; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCue.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCue.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java index 03b437c19..e16b231f7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCue.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; import android.util.Log; -import org.telegram.messenger.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Cue; /** * A representation of a WebVTT cue. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCueParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCueParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java index 3e0bd17a1..6f2a1328c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttCueParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.graphics.Typeface; import android.support.annotation.NonNull; @@ -32,13 +32,14 @@ import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; import android.text.style.UnderlineSpan; import android.util.Log; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -157,7 +158,7 @@ public final class WebvttCueParser { /* package */ static void parseCueText(String id, String markup, WebvttCue.Builder builder, List styles) { SpannableStringBuilder spannedText = new SpannableStringBuilder(); - Stack startTagStack = new Stack<>(); + ArrayDeque startTagStack = new ArrayDeque<>(); List scratchStyleMatches = new ArrayList<>(); int pos = 0; while (pos < markup.length()) { @@ -456,7 +457,7 @@ public final class WebvttCueParser { if (tagExpression.isEmpty()) { return null; } - return tagExpression.split("[ \\.]")[0]; + return Util.splitAtFirst(tagExpression, "[ \\.]")[0]; } private static void getApplicableStyles(List declaredStyles, String id, @@ -518,7 +519,7 @@ public final class WebvttCueParser { voice = fullTagExpression.substring(voiceStartIndex).trim(); fullTagExpression = fullTagExpression.substring(0, voiceStartIndex); } - String[] nameAndClasses = fullTagExpression.split("\\."); + String[] nameAndClasses = Util.split(fullTagExpression, "\\."); String name = nameAndClasses[0]; String[] classes; if (nameAndClasses.length > 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttDecoder.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttDecoder.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java index e5886f119..7c3262fbb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttDecoder.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.text.SimpleSubtitleDecoder; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttParserUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttParserUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java index 8037b4c40..b94be19d8 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttParserUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; -import org.telegram.messenger.exoplayer2.text.SubtitleDecoderException; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -53,8 +54,8 @@ public final class WebvttParserUtil { */ public static long parseTimestampUs(String timestamp) throws NumberFormatException { long value = 0; - String[] parts = timestamp.split("\\.", 2); - String[] subparts = parts[0].split(":"); + String[] parts = Util.splitAtFirst(timestamp, "\\."); + String[] subparts = Util.split(parts[0], ":"); for (String subpart : subparts) { value = (value * 60) + Long.parseLong(subpart); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttSubtitle.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttSubtitle.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttSubtitle.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttSubtitle.java index 3fc2929d7..1dd8000ca 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/text/webvtt/WebvttSubtitle.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttSubtitle.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.text.webvtt; +package com.google.android.exoplayer2.text.webvtt; import android.text.SpannableStringBuilder; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.text.Cue; -import org.telegram.messenger.exoplayer2.text.Subtitle; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.Subtitle; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/AdaptiveTrackSelection.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/AdaptiveTrackSelection.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index fb9e5a68a..64b0da281 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; -import org.telegram.messenger.exoplayer2.upstream.BandwidthMeter; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.Util; import java.util.List; /** @@ -35,7 +36,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { */ public static final class Factory implements TrackSelection.Factory { - private final BandwidthMeter bandwidthMeter; + private final @Nullable BandwidthMeter bandwidthMeter; private final int minDurationForQualityIncreaseMs; private final int maxDurationForQualityDecreaseMs; private final int minDurationToRetainAfterDiscardMs; @@ -44,9 +45,24 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { private final long minTimeBetweenBufferReevaluationMs; private final Clock clock; + /** Creates an adaptive track selection factory with default parameters. */ + public Factory() { + this( + DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS, + DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, + DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, + DEFAULT_BANDWIDTH_FRACTION, + DEFAULT_BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE, + DEFAULT_MIN_TIME_BETWEEN_BUFFER_REEVALUTATION_MS, + Clock.DEFAULT); + } + /** - * @param bandwidthMeter Provides an estimate of the currently available bandwidth. + * @deprecated Use {@link #Factory()} instead. Custom bandwidth meter should be directly passed + * to the player in ExoPlayerFactory. */ + @Deprecated + @SuppressWarnings("deprecation") public Factory(BandwidthMeter bandwidthMeter) { this( bandwidthMeter, @@ -60,7 +76,8 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } /** - * @param bandwidthMeter Provides an estimate of the currently available bandwidth. + * Creates an adaptive track selection factory. + * * @param minDurationForQualityIncreaseMs The minimum duration of buffered data required for the * selected track to switch to one of higher quality. * @param maxDurationForQualityDecreaseMs The maximum duration of buffered data required for the @@ -73,6 +90,27 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { * consider available for use. Setting to a value less than 1 is recommended to account for * inaccuracies in the bandwidth estimator. */ + public Factory( + int minDurationForQualityIncreaseMs, + int maxDurationForQualityDecreaseMs, + int minDurationToRetainAfterDiscardMs, + float bandwidthFraction) { + this( + minDurationForQualityIncreaseMs, + maxDurationForQualityDecreaseMs, + minDurationToRetainAfterDiscardMs, + bandwidthFraction, + DEFAULT_BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE, + DEFAULT_MIN_TIME_BETWEEN_BUFFER_REEVALUTATION_MS, + Clock.DEFAULT); + } + + /** + * @deprecated Use {@link #Factory(int, int, int, float)} instead. Custom bandwidth meter should + * be directly passed to the player in ExoPlayerFactory. + */ + @Deprecated + @SuppressWarnings("deprecation") public Factory( BandwidthMeter bandwidthMeter, int minDurationForQualityIncreaseMs, @@ -91,7 +129,8 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } /** - * @param bandwidthMeter Provides an estimate of the currently available bandwidth.. + * Creates an adaptive track selection factory. + * * @param minDurationForQualityIncreaseMs The minimum duration of buffered data required for the * selected track to switch to one of higher quality. * @param maxDurationForQualityDecreaseMs The maximum duration of buffered data required for the @@ -115,8 +154,33 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { * buffer reevaluation calls. * @param clock A {@link Clock}. */ + @SuppressWarnings("deprecation") public Factory( - BandwidthMeter bandwidthMeter, + int minDurationForQualityIncreaseMs, + int maxDurationForQualityDecreaseMs, + int minDurationToRetainAfterDiscardMs, + float bandwidthFraction, + float bufferedFractionToLiveEdgeForQualityIncrease, + long minTimeBetweenBufferReevaluationMs, + Clock clock) { + this( + /* bandwidthMeter= */ null, + minDurationForQualityIncreaseMs, + maxDurationForQualityDecreaseMs, + minDurationToRetainAfterDiscardMs, + bandwidthFraction, + bufferedFractionToLiveEdgeForQualityIncrease, + minTimeBetweenBufferReevaluationMs, + clock); + } + + /** + * @deprecated Use {@link #Factory(int, int, int, float, float, long, Clock)} instead. Custom + * bandwidth meter should be directly passed to the player in ExoPlayerFactory. + */ + @Deprecated + public Factory( + @Nullable BandwidthMeter bandwidthMeter, int minDurationForQualityIncreaseMs, int maxDurationForQualityDecreaseMs, int minDurationToRetainAfterDiscardMs, @@ -136,7 +200,11 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } @Override - public AdaptiveTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public AdaptiveTrackSelection createTrackSelection( + TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { + if (this.bandwidthMeter != null) { + bandwidthMeter = this.bandwidthMeter; + } return new AdaptiveTrackSelection( group, tracks, @@ -242,9 +310,11 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { this.minTimeBetweenBufferReevaluationMs = minTimeBetweenBufferReevaluationMs; this.clock = clock; playbackSpeed = 1f; - selectedIndex = determineIdealSelectedIndex(Long.MIN_VALUE); reason = C.SELECTION_REASON_INITIAL; lastBufferEvaluationMs = C.TIME_UNSET; + @SuppressWarnings("nullness:method.invocation.invalid") + int selectedIndex = determineIdealSelectedIndex(Long.MIN_VALUE); + this.selectedIndex = selectedIndex; } @Override @@ -301,7 +371,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } @Override - public Object getSelectionData() { + public @Nullable Object getSelectionData() { return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/BaseTrackSelection.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/BaseTrackSelection.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/BaseTrackSelection.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/BaseTrackSelection.java index 7d32dc70b..3f201bcce 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/BaseTrackSelection.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/BaseTrackSelection.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; import android.os.SystemClock; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.util.Assertions; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -110,6 +110,7 @@ public abstract class BaseTrackSelection implements TrackSelection { } @Override + @SuppressWarnings("ReferenceEquality") public final int indexOf(Format format) { for (int i = 0; i < length; i++) { if (formats[i] == format) { @@ -183,7 +184,9 @@ public abstract class BaseTrackSelection implements TrackSelection { return hashCode; } + // Track groups are compared by identity not value, as distinct groups may have the same value. @Override + @SuppressWarnings("ReferenceEquality") public boolean equals(@Nullable Object obj) { if (this == obj) { return true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/DefaultTrackSelector.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/DefaultTrackSelector.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index d5106b631..58784e4c5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -13,30 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; import android.content.Context; import android.graphics.Point; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Pair; import android.util.SparseArray; import android.util.SparseBooleanArray; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.Renderer; -import org.telegram.messenger.exoplayer2.RendererCapabilities; -import org.telegram.messenger.exoplayer2.RendererConfiguration; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.upstream.BandwidthMeter; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.RendererConfiguration; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -44,6 +43,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** * A default {@link TrackSelector} suitable for most use cases. Track selections are made according @@ -56,7 +56,7 @@ import java.util.concurrent.atomic.AtomicReference; * obtain a {@link ParametersBuilder} initialized with the current {@link Parameters}. The desired * modifications can be made on the builder, and the resulting {@link Parameters} can then be built * and set on the selector. For example the following code modifies the parameters to restrict video - * track selections to SD, and to prefer German audio tracks: + * track selections to SD, and to select a German audio track if there is one: * *

    {@code
      * // Build on the current parameters.
    @@ -83,7 +83,7 @@ import java.util.concurrent.atomic.AtomicReference;
      *
      * Selection {@link Parameters} support many different options, some of which are described below.
      *
    - * 

    Track selection overrides

    + *

    Selecting specific tracks

    * * Track selection overrides can be used to select specific tracks. To specify an override for a * renderer, it's first necessary to obtain the tracks that have been mapped to it: @@ -110,13 +110,6 @@ import java.util.concurrent.atomic.AtomicReference; * .setSelectionOverride(rendererIndex, rendererTrackGroups, selectionOverride)); * }
    * - *

    Disabling renderers

    - * - * Renderers can be disabled using {@link ParametersBuilder#setRendererDisabled}. Disabling a - * renderer differs from setting a {@code null} override because the renderer is disabled - * unconditionally, whereas a {@code null} override is applied only when the track groups available - * to the renderer match the {@link TrackGroupArray} for which it was specified. - * *

    Constraint based track selection

    * * Whilst track selection overrides make it possible to select specific tracks, the recommended way @@ -145,6 +138,13 @@ import java.util.concurrent.atomic.AtomicReference; * only applied to periods whose tracks match those for which the override was set. * * + *

    Disabling renderers

    + * + * Renderers can be disabled using {@link ParametersBuilder#setRendererDisabled}. Disabling a + * renderer differs from setting a {@code null} override because the renderer is disabled + * unconditionally, whereas a {@code null} override is applied only when the track groups available + * to the renderer match the {@link TrackGroupArray} for which it was specified. + * *

    Tunneling

    * * Tunneled playback can be enabled in cases where the combination of renderers and selected tracks @@ -154,15 +154,16 @@ import java.util.concurrent.atomic.AtomicReference; public class DefaultTrackSelector extends MappingTrackSelector { /** - * A builder for {@link Parameters}. + * A builder for {@link Parameters}. See the {@link Parameters} documentation for explanations of + * the parameters that can be configured using this builder. */ public static final class ParametersBuilder { private final SparseArray> selectionOverrides; private final SparseBooleanArray rendererDisabledFlags; - private String preferredAudioLanguage; - private String preferredTextLanguage; + private @Nullable String preferredAudioLanguage; + private @Nullable String preferredTextLanguage; private boolean selectUndeterminedTextLanguage; private int disabledTextTrackSelectionFlags; private boolean forceLowestBitrate; @@ -178,9 +179,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { private boolean viewportOrientationMayChange; private int tunnelingAudioSessionId; - /** - * Creates a builder obtaining the initial values from {@link Parameters#DEFAULT}. - */ + /** Creates a builder with default initial values. */ public ParametersBuilder() { this(Parameters.DEFAULT); } @@ -344,15 +343,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * Equivalent to invoking {@link #setViewportSize} with the viewport size obtained from - * {@link Util#getPhysicalDisplaySize(Context)}. + * Equivalent to calling {@link #setViewportSize(int, int, boolean)} with the viewport size + * obtained from {@link Util#getPhysicalDisplaySize(Context)}. * - * @param context The context to obtain the viewport size from. - * @param viewportOrientationMayChange See {@link #viewportOrientationMayChange}. + * @param context Any context. + * @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. * @return This builder. */ - public ParametersBuilder setViewportSizeToPhysicalDisplaySize(Context context, - boolean viewportOrientationMayChange) { + public ParametersBuilder setViewportSizeToPhysicalDisplaySize( + Context context, boolean viewportOrientationMayChange) { // Assume the viewport is fullscreen. Point viewportSize = Util.getPhysicalDisplaySize(context); return setViewportSize(viewportSize.x, viewportSize.y, viewportOrientationMayChange); @@ -369,13 +368,16 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and - * {@link Parameters#viewportOrientationMayChange}. + * See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and {@link + * Parameters#viewportOrientationMayChange}. * + * @param viewportWidth See {@link Parameters#viewportWidth}. + * @param viewportHeight See {@link Parameters#viewportHeight}. + * @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. * @return This builder. */ - public ParametersBuilder setViewportSize(int viewportWidth, int viewportHeight, - boolean viewportOrientationMayChange) { + public ParametersBuilder setViewportSize( + int viewportWidth, int viewportHeight, boolean viewportOrientationMayChange) { this.viewportWidth = viewportWidth; this.viewportHeight = viewportHeight; this.viewportOrientationMayChange = viewportOrientationMayChange; @@ -486,8 +488,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in - * tunneling mode. Session ids can be generated using {@link + * See {@link Parameters#tunnelingAudioSessionId}. + * + *

    Enables or disables tunneling. To enable tunneling, pass an audio session id to use when + * in tunneling mode. Session ids can be generated using {@link * C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link * C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and * supported by the audio and video renderers for the selected tracks. @@ -541,25 +545,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** Constraint parameters for {@link DefaultTrackSelector}. */ public static final class Parameters implements Parcelable { - /** - * An instance with default values: - * - *

      - *
    • No preferred audio language. - *
    • No preferred text language. - *
    • Text tracks with undetermined language are not selected if no track with {@link - * #preferredTextLanguage} is available. - *
    • All selection flags are considered for text track selections. - *
    • Lowest bitrate track selections are not forced. - *
    • Adaptation between different mime types is not allowed. - *
    • Non seamless adaptation is allowed. - *
    • No max limit for video width/height. - *
    • No max video bitrate. - *
    • Video constraints are exceeded if no supported selection can be made otherwise. - *
    • Renderer capabilities are exceeded if no supported selection can be made. - *
    • No viewport constraints. - *
    - */ + /** An instance with default values. */ public static final Parameters DEFAULT = new Parameters(); // Per renderer overrides. @@ -569,112 +555,138 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Audio /** - * The preferred language for audio, as well as for forced text tracks, as an ISO 639-2/T tag. - * {@code null} selects the default track, or the first track if there's no default. + * The preferred language for audio and forced text tracks, as an ISO 639-2/T tag. {@code null} + * selects the default track, or the first track if there's no default. The default value is + * {@code null}. */ - public final String preferredAudioLanguage; + public final @Nullable String preferredAudioLanguage; // Text /** * The preferred language for text tracks as an ISO 639-2/T tag. {@code null} selects the - * default track if there is one, or no track otherwise. + * default track if there is one, or no track otherwise. The default value is {@code null}. */ - public final String preferredTextLanguage; + public final @Nullable String preferredTextLanguage; /** - * Whether a text track with undetermined language should be selected if no track with - * {@link #preferredTextLanguage} is available, or if {@link #preferredTextLanguage} is unset. + * Whether a text track with undetermined language should be selected if no track with {@link + * #preferredTextLanguage} is available, or if {@link #preferredTextLanguage} is unset. The + * default value is {@code false}. */ public final boolean selectUndeterminedTextLanguage; /** * Bitmask of selection flags that are disabled for text track selections. See {@link - * C.SelectionFlags}. + * C.SelectionFlags}. The default value is {@code 0} (i.e. no flags). */ public final int disabledTextTrackSelectionFlags; // Video /** - * Maximum allowed video width. + * Maximum allowed video width. The default value is {@link Integer#MAX_VALUE} (i.e. no + * constraint). + * + *

    To constrain adaptive video track selections to be suitable for a given viewport (the + * region of the display within which video will be played), use ({@link #viewportWidth}, {@link + * #viewportHeight} and {@link #viewportOrientationMayChange}) instead. */ public final int maxVideoWidth; /** - * Maximum allowed video height. + * Maximum allowed video height. The default value is {@link Integer#MAX_VALUE} (i.e. no + * constraint). + * + *

    To constrain adaptive video track selections to be suitable for a given viewport (the + * region of the display within which video will be played), use ({@link #viewportWidth}, {@link + * #viewportHeight} and {@link #viewportOrientationMayChange}) instead. */ public final int maxVideoHeight; /** - * Maximum video bitrate. + * Maximum video bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint). */ public final int maxVideoBitrate; /** - * Whether to exceed video constraints when no selection can be made otherwise. + * Whether to exceed the {@link #maxVideoWidth}, {@link #maxVideoHeight} and {@link + * #maxVideoBitrate} constraints when no selection can be made otherwise. The default value is + * {@code true}. */ public final boolean exceedVideoConstraintsIfNecessary; /** - * Viewport width in pixels. Constrains video tracks selections for adaptive playbacks so that - * only tracks suitable for the viewport are selected. + * Viewport width in pixels. Constrains video track selections for adaptive content so that only + * tracks suitable for the viewport are selected. The default value is {@link Integer#MAX_VALUE} + * (i.e. no constraint). */ public final int viewportWidth; /** - * Viewport height in pixels. Constrains video tracks selections for adaptive playbacks so that - * only tracks suitable for the viewport are selected. + * Viewport height in pixels. Constrains video track selections for adaptive content so that + * only tracks suitable for the viewport are selected. The default value is {@link + * Integer#MAX_VALUE} (i.e. no constraint). */ public final int viewportHeight; /** - * Whether the viewport orientation may change during playback. Constrains video tracks - * selections for adaptive playbacks so that only tracks suitable for the viewport are selected. + * Whether the viewport orientation may change during playback. Constrains video track + * selections for adaptive content so that only tracks suitable for the viewport are selected. + * The default value is {@code true}. */ public final boolean viewportOrientationMayChange; // General /** * Whether to force selection of the single lowest bitrate audio and video tracks that comply - * with all other constraints. + * with all other constraints. The default value is {@code false}. */ public final boolean forceLowestBitrate; /** - * Whether to allow adaptive selections containing mixed mime types. + * Whether to allow adaptive selections containing mixed mime types. The default value is {@code + * false}. */ public final boolean allowMixedMimeAdaptiveness; /** - * Whether to allow adaptive selections where adaptation may not be completely seamless. + * Whether to allow adaptive selections where adaptation may not be completely seamless. The + * default value is {@code true}. */ public final boolean allowNonSeamlessAdaptiveness; /** * Whether to exceed renderer capabilities when no selection can be made otherwise. + * + *

    This parameter applies when all of the tracks available for a renderer exceed the + * renderer's reported capabilities. If the parameter is {@code true} then the lowest quality + * track will still be selected. Playback may succeed if the renderer has under-reported its + * true capabilities. If {@code false} then no track will be selected. The default value is + * {@code true}. */ public final boolean exceedRendererCapabilitiesIfNecessary; /** * The audio session id to use when tunneling, or {@link C#AUDIO_SESSION_ID_UNSET} if tunneling - * is not to be enabled. + * is disabled. The default value is {@link C#AUDIO_SESSION_ID_UNSET} (i.e. tunneling is + * disabled). */ public final int tunnelingAudioSessionId; private Parameters() { this( - new SparseArray>(), - new SparseBooleanArray(), - null, - null, - false, - 0, - false, - false, - true, - Integer.MAX_VALUE, - Integer.MAX_VALUE, - Integer.MAX_VALUE, - true, - true, - Integer.MAX_VALUE, - Integer.MAX_VALUE, - true, - C.AUDIO_SESSION_ID_UNSET); + /* selectionOverrides= */ new SparseArray<>(), + /* rendererDisabledFlags= */ new SparseBooleanArray(), + /* preferredAudioLanguage= */ null, + /* preferredTextLanguage= */ null, + /* selectUndeterminedTextLanguage= */ false, + /* disabledTextTrackSelectionFlags= */ 0, + /* forceLowestBitrate= */ false, + /* allowMixedMimeAdaptiveness= */ false, + /* allowNonSeamlessAdaptiveness= */ true, + /* maxVideoWidth= */ Integer.MAX_VALUE, + /* maxVideoHeight= */ Integer.MAX_VALUE, + /* maxVideoBitrate= */ Integer.MAX_VALUE, + /* exceedVideoConstraintsIfNecessary= */ true, + /* exceedRendererCapabilitiesIfNecessary= */ true, + /* viewportWidth= */ Integer.MAX_VALUE, + /* viewportHeight= */ Integer.MAX_VALUE, + /* viewportOrientationMayChange= */ true, + /* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET); } /* package */ Parameters( SparseArray> selectionOverrides, SparseBooleanArray rendererDisabledFlags, - String preferredAudioLanguage, - String preferredTextLanguage, + @Nullable String preferredAudioLanguage, + @Nullable String preferredTextLanguage, boolean selectUndeterminedTextLanguage, int disabledTextTrackSelectionFlags, boolean forceLowestBitrate, @@ -759,7 +771,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @param groups The {@link TrackGroupArray}. * @return The override, or null if no override exists. */ - public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) { + public final @Nullable SelectionOverride getSelectionOverride( + int rendererIndex, TrackGroupArray groups) { Map overrides = selectionOverrides.get(rendererIndex); return overrides != null ? overrides.get(groups) : null; } @@ -816,8 +829,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { result = 31 * result + viewportHeight; result = 31 * result + maxVideoBitrate; result = 31 * result + tunnelingAudioSessionId; - result = 31 * result + preferredAudioLanguage.hashCode(); - result = 31 * result + preferredTextLanguage.hashCode(); + result = + 31 * result + (preferredAudioLanguage == null ? 0 : preferredAudioLanguage.hashCode()); + result = 31 * result + (preferredTextLanguage == null ? 0 : preferredTextLanguage.hashCode()); return result; } @@ -1045,20 +1059,16 @@ public class DefaultTrackSelector extends MappingTrackSelector { private final TrackSelection.Factory adaptiveTrackSelectionFactory; private final AtomicReference parametersReference; - /** - * Constructs an instance that does not support adaptive track selection. - */ + /** Constructs an instance that uses a default factory to create adaptive track selections. */ public DefaultTrackSelector() { - this((TrackSelection.Factory) null); + this(new AdaptiveTrackSelection.Factory()); } /** - * Constructs an instance that supports adaptive track selection. Adaptive track selections use - * the provided {@link BandwidthMeter} to determine which individual track should be used during - * playback. - * - * @param bandwidthMeter The {@link BandwidthMeter}. + * @deprecated Use {@link #DefaultTrackSelector()} instead. Custom bandwidth meter should be + * directly passed to the player in ExoPlayerFactory. */ + @Deprecated public DefaultTrackSelector(BandwidthMeter bandwidthMeter) { this(new AdaptiveTrackSelection.Factory(bandwidthMeter)); } @@ -1066,8 +1076,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** * Constructs an instance that uses a factory to create adaptive track selections. * - * @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s, or null if - * the selector should not support adaptive tracks. + * @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s. */ public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) { this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory; @@ -1139,7 +1148,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** @deprecated Use {@link Parameters#getSelectionOverride(int, TrackGroupArray)}. */ @Deprecated - public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) { + public final @Nullable SelectionOverride getSelectionOverride( + int rendererIndex, TrackGroupArray groups) { return getParameters().getSelectionOverride(rendererIndex, groups); } @@ -1170,14 +1180,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { // MappingTrackSelector implementation. @Override - protected final Pair selectTracks( - MappedTrackInfo mappedTrackInfo, - int[][][] rendererFormatSupports, - int[] rendererMixedMimeTypeAdaptationSupports) - throws ExoPlaybackException { + protected final Pair<@NullableType RendererConfiguration[], @NullableType TrackSelection[]> + selectTracks( + MappedTrackInfo mappedTrackInfo, + int[][][] rendererFormatSupports, + int[] rendererMixedMimeTypeAdaptationSupports) + throws ExoPlaybackException { Parameters params = parametersReference.get(); int rendererCount = mappedTrackInfo.getRendererCount(); - TrackSelection[] rendererTrackSelections = + @NullableType TrackSelection[] rendererTrackSelections = selectAllTracks( mappedTrackInfo, rendererFormatSupports, @@ -1200,8 +1211,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { rendererTrackGroups.get(override.groupIndex), override.tracks[0]); } else { rendererTrackSelections[i] = - adaptiveTrackSelectionFactory.createTrackSelection( - rendererTrackGroups.get(override.groupIndex), override.tracks); + Assertions.checkNotNull(adaptiveTrackSelectionFactory) + .createTrackSelection( + rendererTrackGroups.get(override.groupIndex), + getBandwidthMeter(), + override.tracks); } } } @@ -1209,7 +1223,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Initialize the renderer configurations to the default configuration for all renderers with // selections, and null otherwise. - RendererConfiguration[] rendererConfigurations = new RendererConfiguration[rendererCount]; + @NullableType RendererConfiguration[] rendererConfigurations = + new RendererConfiguration[rendererCount]; for (int i = 0; i < rendererCount; i++) { boolean forceRendererDisabled = params.getRendererDisabled(i); boolean rendererEnabled = @@ -1248,14 +1263,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { * disabled, unless RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected TrackSelection[] selectAllTracks( + protected @NullableType TrackSelection[] selectAllTracks( MappedTrackInfo mappedTrackInfo, int[][][] rendererFormatSupports, int[] rendererMixedMimeTypeAdaptationSupports, Parameters params) throws ExoPlaybackException { int rendererCount = mappedTrackInfo.getRendererCount(); - TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount]; + @NullableType TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount]; boolean seenVideoRendererWithMappedTracks = false; boolean selectedVideoTracks = false; @@ -1331,12 +1346,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @return The {@link TrackSelection} for the renderer, or null if no selection was made. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected TrackSelection selectVideoTrack( + protected @Nullable TrackSelection selectVideoTrack( TrackGroupArray groups, int[][] formatSupports, int mixedMimeTypeAdaptationSupports, Parameters params, - TrackSelection.Factory adaptiveTrackSelectionFactory) + @Nullable TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException { TrackSelection selection = null; if (!params.forceLowestBitrate && adaptiveTrackSelectionFactory != null) { @@ -1346,7 +1361,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { formatSupports, mixedMimeTypeAdaptationSupports, params, - adaptiveTrackSelectionFactory); + adaptiveTrackSelectionFactory, + getBandwidthMeter()); } if (selection == null) { selection = selectFixedVideoTrack(groups, formatSupports, params); @@ -1354,12 +1370,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { return selection; } - private static TrackSelection selectAdaptiveVideoTrack( + private static @Nullable TrackSelection selectAdaptiveVideoTrack( TrackGroupArray groups, int[][] formatSupport, int mixedMimeTypeAdaptationSupports, Parameters params, - TrackSelection.Factory adaptiveTrackSelectionFactory) + TrackSelection.Factory adaptiveTrackSelectionFactory, + BandwidthMeter bandwidthMeter) throws ExoPlaybackException { int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) @@ -1374,7 +1391,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { params.maxVideoBitrate, params.viewportWidth, params.viewportHeight, params.viewportOrientationMayChange); if (adaptiveTracks.length > 0) { - return adaptiveTrackSelectionFactory.createTrackSelection(group, adaptiveTracks); + return Assertions.checkNotNull(adaptiveTrackSelectionFactory) + .createTrackSelection(group, bandwidthMeter, adaptiveTracks); } } return null; @@ -1397,7 +1415,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { String selectedMimeType = null; if (!allowMixedMimeTypes) { // Select the mime type for which we have the most adaptive tracks. - HashSet seenMimeTypes = new HashSet<>(); + HashSet<@NullableType String> seenMimeTypes = new HashSet<>(); int selectedMimeTypeTrackCount = 0; for (int i = 0; i < selectedTrackIndices.size(); i++) { int trackIndex = selectedTrackIndices.get(i); @@ -1421,9 +1439,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { return selectedTrackIndices.size() < 2 ? NO_TRACKS : Util.toArray(selectedTrackIndices); } - private static int getAdaptiveVideoTrackCountForMimeType(TrackGroup group, int[] formatSupport, - int requiredAdaptiveSupport, String mimeType, int maxVideoWidth, int maxVideoHeight, - int maxVideoBitrate, List selectedTrackIndices) { + private static int getAdaptiveVideoTrackCountForMimeType( + TrackGroup group, + int[] formatSupport, + int requiredAdaptiveSupport, + @Nullable String mimeType, + int maxVideoWidth, + int maxVideoHeight, + int maxVideoBitrate, + List selectedTrackIndices) { int adaptiveTrackCount = 0; for (int i = 0; i < selectedTrackIndices.size(); i++) { int trackIndex = selectedTrackIndices.get(i); @@ -1436,9 +1460,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { return adaptiveTrackCount; } - private static void filterAdaptiveVideoTrackCountForMimeType(TrackGroup group, - int[] formatSupport, int requiredAdaptiveSupport, String mimeType, int maxVideoWidth, - int maxVideoHeight, int maxVideoBitrate, List selectedTrackIndices) { + private static void filterAdaptiveVideoTrackCountForMimeType( + TrackGroup group, + int[] formatSupport, + int requiredAdaptiveSupport, + @Nullable String mimeType, + int maxVideoWidth, + int maxVideoHeight, + int maxVideoBitrate, + List selectedTrackIndices) { for (int i = selectedTrackIndices.size() - 1; i >= 0; i--) { int trackIndex = selectedTrackIndices.get(i); if (!isSupportedAdaptiveVideoTrack(group.getFormat(trackIndex), mimeType, @@ -1449,8 +1479,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { } } - private static boolean isSupportedAdaptiveVideoTrack(Format format, String mimeType, - int formatSupport, int requiredAdaptiveSupport, int maxVideoWidth, int maxVideoHeight, + private static boolean isSupportedAdaptiveVideoTrack( + Format format, + @Nullable String mimeType, + int formatSupport, + int requiredAdaptiveSupport, + int maxVideoWidth, + int maxVideoHeight, int maxVideoBitrate) { return isSupported(formatSupport, false) && ((formatSupport & requiredAdaptiveSupport) != 0) && (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType)) @@ -1459,7 +1494,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { && (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate); } - private static TrackSelection selectFixedVideoTrack( + private static @Nullable TrackSelection selectFixedVideoTrack( TrackGroupArray groups, int[][] formatSupports, Parameters params) { TrackGroup selectedGroup = null; int selectedTrackIndex = 0; @@ -1537,12 +1572,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @return The {@link TrackSelection} for the renderer, or null if no selection was made. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected TrackSelection selectAudioTrack( + protected @Nullable TrackSelection selectAudioTrack( TrackGroupArray groups, int[][] formatSupports, int mixedMimeTypeAdaptationSupports, Parameters params, - TrackSelection.Factory adaptiveTrackSelectionFactory) + @Nullable TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException { int selectedTrackIndex = C.INDEX_UNSET; int selectedGroupIndex = C.INDEX_UNSET; @@ -1576,8 +1611,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { getAdaptiveAudioTracks( selectedGroup, formatSupports[selectedGroupIndex], params.allowMixedMimeAdaptiveness); if (adaptiveTracks.length > 0) { - return adaptiveTrackSelectionFactory.createTrackSelection(selectedGroup, - adaptiveTracks); + return adaptiveTrackSelectionFactory + .createTrackSelection(selectedGroup, getBandwidthMeter(), adaptiveTracks); } } return new FixedTrackSelection(selectedGroup, selectedTrackIndex); @@ -1606,8 +1641,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { int[] adaptiveIndices = new int[selectedConfigurationTrackCount]; int index = 0; for (int i = 0; i < group.length; i++) { - if (isSupportedAdaptiveAudioTrack(group.getFormat(i), formatSupport[i], - selectedConfiguration)) { + if (isSupportedAdaptiveAudioTrack( + group.getFormat(i), formatSupport[i], Assertions.checkNotNull(selectedConfiguration))) { adaptiveIndices[index++] = i; } } @@ -1648,7 +1683,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @return The {@link TrackSelection} for the renderer, or null if no selection was made. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected TrackSelection selectTextTrack( + protected @Nullable TrackSelection selectTextTrack( TrackGroupArray groups, int[][] formatSupport, Parameters params) throws ExoPlaybackException { TrackGroup selectedGroup = null; @@ -1721,7 +1756,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @return The {@link TrackSelection} for the renderer, or null if no selection was made. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected TrackSelection selectOtherTrack( + protected @Nullable TrackSelection selectOtherTrack( int trackType, TrackGroupArray groups, int[][] formatSupport, Parameters params) throws ExoPlaybackException { TrackGroup selectedGroup = null; @@ -1768,8 +1803,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { private static void maybeConfigureRenderersForTunneling( MappedTrackInfo mappedTrackInfo, int[][][] renderererFormatSupports, - RendererConfiguration[] rendererConfigurations, - TrackSelection[] trackSelections, + @NullableType RendererConfiguration[] rendererConfigurations, + @NullableType TrackSelection[] trackSelections, int tunnelingAudioSessionId) { if (tunnelingAudioSessionId == C.AUDIO_SESSION_ID_UNSET) { return; @@ -1883,15 +1918,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * Returns whether a {@link Format} specifies a particular language, or {@code false} if - * {@code language} is null. + * Returns whether a {@link Format} specifies a particular language, or {@code false} if {@code + * language} is null. * * @param format The {@link Format}. * @param language The language. * @return Whether the format specifies the language, or {@code false} if {@code language} is * null. */ - protected static boolean formatHasLanguage(Format format, String language) { + protected static boolean formatHasLanguage(Format format, @Nullable String language) { return language != null && TextUtils.equals(language, Util.normalizeLanguageCode(format.language)); } @@ -1997,7 +2032,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * negative integer if this score is worse than the other. */ @Override - public int compareTo(@NonNull AudioTrackScore other) { + public int compareTo(AudioTrackScore other) { if (this.withinRendererCapabilitiesScore != other.withinRendererCapabilitiesScore) { return compareInts(this.withinRendererCapabilitiesScore, other.withinRendererCapabilitiesScore); @@ -2066,9 +2101,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { public final int channelCount; public final int sampleRate; - public final String mimeType; + public final @Nullable String mimeType; - public AudioConfigurationTuple(int channelCount, int sampleRate, String mimeType) { + public AudioConfigurationTuple(int channelCount, int sampleRate, @Nullable String mimeType) { this.channelCount = channelCount; this.sampleRate = sampleRate; this.mimeType = mimeType; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/FixedTrackSelection.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java similarity index 78% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/FixedTrackSelection.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java index 223ff5b4c..b41698521 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/FixedTrackSelection.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; /** * A {@link TrackSelection} consisting of a single track. @@ -30,7 +32,7 @@ public final class FixedTrackSelection extends BaseTrackSelection { public static final class Factory implements TrackSelection.Factory { private final int reason; - private final Object data; + private final @Nullable Object data; public Factory() { this.reason = C.SELECTION_REASON_UNKNOWN; @@ -41,21 +43,21 @@ public final class FixedTrackSelection extends BaseTrackSelection { * @param reason A reason for the track selection. * @param data Optional data associated with the track selection. */ - public Factory(int reason, Object data) { + public Factory(int reason, @Nullable Object data) { this.reason = reason; this.data = data; } @Override - public FixedTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public FixedTrackSelection createTrackSelection( + TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { Assertions.checkArgument(tracks.length == 1); return new FixedTrackSelection(group, tracks[0], reason, data); } - } private final int reason; - private final Object data; + private final @Nullable Object data; /** * @param group The {@link TrackGroup}. Must not be null. @@ -71,7 +73,7 @@ public final class FixedTrackSelection extends BaseTrackSelection { * @param reason A reason for the track selection. * @param data Optional data associated with the track selection. */ - public FixedTrackSelection(TrackGroup group, int track, int reason, Object data) { + public FixedTrackSelection(TrackGroup group, int track, int reason, @Nullable Object data) { super(group, track); this.reason = reason; this.data = data; @@ -94,7 +96,7 @@ public final class FixedTrackSelection extends BaseTrackSelection { } @Override - public Object getSelectionData() { + public @Nullable Object getSelectionData() { return data; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/MappingTrackSelector.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/MappingTrackSelector.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java index 46ff6c1fc..99e4e58c4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/MappingTrackSelector.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java @@ -13,21 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; import android.support.annotation.IntDef; +import android.support.annotation.Nullable; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Renderer; -import org.telegram.messenger.exoplayer2.RendererCapabilities; -import org.telegram.messenger.exoplayer2.RendererConfiguration; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.RendererConfiguration; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** * Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s @@ -301,13 +303,13 @@ public abstract class MappingTrackSelector extends TrackSelector { } - private MappedTrackInfo currentMappedTrackInfo; + private @Nullable MappedTrackInfo currentMappedTrackInfo; /** * Returns the mapping information for the currently active track selection, or null if no * selection is currently active. */ - public final MappedTrackInfo getCurrentMappedTrackInfo() { + public final @Nullable MappedTrackInfo getCurrentMappedTrackInfo() { return currentMappedTrackInfo; } @@ -357,9 +359,11 @@ public abstract class MappingTrackSelector extends TrackSelector { int[] rendererTrackTypes = new int[rendererCapabilities.length]; for (int i = 0; i < rendererCapabilities.length; i++) { int rendererTrackGroupCount = rendererTrackGroupCounts[i]; - rendererTrackGroupArrays[i] = new TrackGroupArray( - Arrays.copyOf(rendererTrackGroups[i], rendererTrackGroupCount)); - rendererFormatSupports[i] = Arrays.copyOf(rendererFormatSupports[i], rendererTrackGroupCount); + rendererTrackGroupArrays[i] = + new TrackGroupArray( + Util.nullSafeArrayCopy(rendererTrackGroups[i], rendererTrackGroupCount)); + rendererFormatSupports[i] = + Util.nullSafeArrayCopy(rendererFormatSupports[i], rendererTrackGroupCount); rendererTrackTypes[i] = rendererCapabilities[i].getTrackType(); } @@ -367,7 +371,7 @@ public abstract class MappingTrackSelector extends TrackSelector { int unmappedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length]; TrackGroupArray unmappedTrackGroupArray = new TrackGroupArray( - Arrays.copyOf( + Util.nullSafeArrayCopy( rendererTrackGroups[rendererCapabilities.length], unmappedTrackGroupCount)); // Package up the track information and selections. @@ -379,7 +383,7 @@ public abstract class MappingTrackSelector extends TrackSelector { rendererFormatSupports, unmappedTrackGroupArray); - Pair result = + Pair<@NullableType RendererConfiguration[], @NullableType TrackSelection[]> result = selectTracks( mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports); return new TrackSelectorResult(result.first, result.second, mappedTrackInfo); @@ -399,11 +403,12 @@ public abstract class MappingTrackSelector extends TrackSelector { * RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ - protected abstract Pair selectTracks( - MappedTrackInfo mappedTrackInfo, - int[][][] rendererFormatSupports, - int[] rendererMixedMimeTypeAdaptationSupport) - throws ExoPlaybackException; + protected abstract Pair<@NullableType RendererConfiguration[], @NullableType TrackSelection[]> + selectTracks( + MappedTrackInfo mappedTrackInfo, + int[][][] rendererFormatSupports, + int[] rendererMixedMimeTypeAdaptationSupport) + throws ExoPlaybackException; /** * Finds the renderer to which the provided {@link TrackGroup} should be mapped. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/RandomTrackSelection.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/RandomTrackSelection.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java index 185570ff7..2ea90761a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/RandomTrackSelection.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; import android.os.SystemClock; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.source.TrackGroup; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import java.util.Random; /** @@ -44,10 +46,10 @@ public final class RandomTrackSelection extends BaseTrackSelection { } @Override - public RandomTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public RandomTrackSelection createTrackSelection( + TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { return new RandomTrackSelection(group, tracks, random); } - } private final Random random; @@ -123,7 +125,7 @@ public final class RandomTrackSelection extends BaseTrackSelection { } @Override - public Object getSelectionData() { + public @Nullable Object getSelectionData() { return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelection.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelection.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java index d21fc5f1b..0650159cf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelection.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.chunk.MediaChunk; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import java.util.List; /** @@ -39,12 +41,13 @@ public interface TrackSelection { * Creates a new selection. * * @param group The {@link TrackGroup}. Must not be null. + * @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks. * @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be * null or empty. May be in any order. * @return The created selection. */ - TrackSelection createTrackSelection(TrackGroup group, int... tracks); - + TrackSelection createTrackSelection( + TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks); } /** @@ -90,7 +93,9 @@ public interface TrackSelection { int getIndexInTrackGroup(int index); /** - * Returns the index in the selection of the track with the specified format. + * Returns the index in the selection of the track with the specified format. The format is + * located by identity so, for example, {@code selection.indexOf(selection.getFormat(index)) == + * index} even if multiple selected tracks have formats that contain the same values. * * @param format The format. * @return The index in the selection, or {@link C#INDEX_UNSET} if the track with the specified @@ -129,10 +134,8 @@ public interface TrackSelection { */ int getSelectionReason(); - /** - * Returns optional data associated with the current track selection. - */ - Object getSelectionData(); + /** Returns optional data associated with the current track selection. */ + @Nullable Object getSelectionData(); // Adaptation. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectionArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionArray.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectionArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionArray.java index 1bba2ffb1..48151002b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectionArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionArray.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; import android.support.annotation.Nullable; import java.util.Arrays; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** An array of {@link TrackSelection}s. */ public final class TrackSelectionArray { @@ -24,15 +25,13 @@ public final class TrackSelectionArray { /** The length of this array. */ public final int length; - private final TrackSelection[] trackSelections; + private final @NullableType TrackSelection[] trackSelections; // Lazily initialized hashcode. private int hashCode; - /** - * @param trackSelections The selections. Must not be null, but may contain null elements. - */ - public TrackSelectionArray(TrackSelection... trackSelections) { + /** @param trackSelections The selections. Must not be null, but may contain null elements. */ + public TrackSelectionArray(@NullableType TrackSelection... trackSelections) { this.trackSelections = trackSelections; this.length = trackSelections.length; } @@ -43,14 +42,12 @@ public final class TrackSelectionArray { * @param index The index of the selection. * @return The selection. */ - public TrackSelection get(int index) { + public @Nullable TrackSelection get(int index) { return trackSelections[index]; } - /** - * Returns the selections in a newly allocated array. - */ - public TrackSelection[] getAll() { + /** Returns the selections in a newly allocated array. */ + public @NullableType TrackSelection[] getAll() { return trackSelections.clone(); } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java new file mode 100755 index 000000000..3bb603318 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.trackselection; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.RendererConfiguration; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; + +/** + * The component of an {@link ExoPlayer} responsible for selecting tracks to be consumed by each of + * the player's {@link Renderer}s. The {@link DefaultTrackSelector} implementation should be + * suitable for most use cases. + * + *

    Interactions with the player

    + * + * The following interactions occur between the player and its track selector during playback. + * + *

    + * + *

      + *
    • When the player is created it will initialize the track selector by calling {@link + * #init(InvalidationListener, BandwidthMeter)}. + *
    • When the player needs to make a track selection it will call {@link + * #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the start + * of playback, when the player starts to buffer a new period of the media being played, and + * when the track selector invalidates its previous selections. + *
    • The player may perform a track selection well in advance of the selected tracks becoming + * active, where active is defined to mean that the renderers are actually consuming media + * corresponding to the selection that was made. For example when playing media containing + * multiple periods, the track selection for a period is made when the player starts to buffer + * that period. Hence if the player's buffering policy is to maintain a 30 second buffer, the + * selection will occur approximately 30 seconds in advance of it becoming active. In fact the + * selection may never become active, for example if the user seeks to some other period of + * the media during the 30 second gap. The player indicates to the track selector when a + * selection it has previously made becomes active by calling {@link + * #onSelectionActivated(Object)}. + *
    • If the track selector wishes to indicate to the player that selections it has previously + * made are invalid, it can do so by calling {@link + * InvalidationListener#onTrackSelectionsInvalidated()} on the {@link InvalidationListener} + * that was passed to {@link #init(InvalidationListener, BandwidthMeter)}. A track selector + * may wish to do this if its configuration has changed, for example if it now wishes to + * prefer audio tracks in a particular language. This will trigger the player to make new + * track selections. Note that the player will have to re-buffer in the case that the new + * track selection for the currently playing period differs from the one that was invalidated. + *
    + * + *

    Renderer configuration

    + * + * The {@link TrackSelectorResult} returned by {@link #selectTracks(RendererCapabilities[], + * TrackGroupArray)} contains not only {@link TrackSelection}s for each renderer, but also {@link + * RendererConfiguration}s defining configuration parameters that the renderers should apply when + * consuming the corresponding media. Whilst it may seem counter-intuitive for a track selector to + * also specify renderer configuration information, in practice the two are tightly bound together. + * It may only be possible to play a certain combination tracks if the renderers are configured in a + * particular way. Equally, it may only be possible to configure renderers in a particular way if + * certain tracks are selected. Hence it makes sense to determined the track selection and + * corresponding renderer configurations in a single step. + * + *

    Threading model

    + * + * All calls made by the player into the track selector are on the player's internal playback + * thread. The track selector may call {@link InvalidationListener#onTrackSelectionsInvalidated()} + * from any thread. + */ +public abstract class TrackSelector { + + /** + * Notified when selections previously made by a {@link TrackSelector} are no longer valid. + */ + public interface InvalidationListener { + + /** + * Called by a {@link TrackSelector} to indicate that selections it has previously made are no + * longer valid. May be called from any thread. + */ + void onTrackSelectionsInvalidated(); + + } + + private @Nullable InvalidationListener listener; + private @Nullable BandwidthMeter bandwidthMeter; + + /** + * Called by the player to initialize the selector. + * + * @param listener An invalidation listener that the selector can call to indicate that selections + * it has previously made are no longer valid. + * @param bandwidthMeter A bandwidth meter which can be used by track selections to select tracks. + */ + public final void init(InvalidationListener listener, BandwidthMeter bandwidthMeter) { + this.listener = listener; + this.bandwidthMeter = bandwidthMeter; + } + + /** + * Called by the player to perform a track selection. + * + * @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which tracks + * are to be selected. + * @param trackGroups The available track groups. + * @return A {@link TrackSelectorResult} describing the track selections. + * @throws ExoPlaybackException If an error occurs selecting tracks. + */ + public abstract TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, + TrackGroupArray trackGroups) throws ExoPlaybackException; + + /** + * Called by the player when a {@link TrackSelectorResult} previously generated by + * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} is activated. + * + * @param info The value of {@link TrackSelectorResult#info} in the activated selection. + */ + public abstract void onSelectionActivated(Object info); + + /** + * Calls {@link InvalidationListener#onTrackSelectionsInvalidated()} to invalidate all previously + * generated track selections. + */ + protected final void invalidate() { + if (listener != null) { + listener.onTrackSelectionsInvalidated(); + } + } + + /** + * Returns a bandwidth meter which can be used by track selections to select tracks. Must only be + * called after {@link #init(InvalidationListener, BandwidthMeter)} has been called. + */ + protected final BandwidthMeter getBandwidthMeter() { + return Assertions.checkNotNull(bandwidthMeter); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectorResult.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectorResult.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java index 8854bb39b..f1136f0be 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelectorResult.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.trackselection; +package com.google.android.exoplayer2.trackselection; -import org.telegram.messenger.exoplayer2.RendererConfiguration; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.RendererConfiguration; +import com.google.android.exoplayer2.util.Util; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** * The result of a {@link TrackSelector} operation. @@ -29,7 +30,7 @@ public final class TrackSelectorResult { * A {@link RendererConfiguration} for each renderer. A null entry indicates the corresponding * renderer should be disabled. */ - public final RendererConfiguration[] rendererConfigurations; + public final @NullableType RendererConfiguration[] rendererConfigurations; /** * A {@link TrackSelectionArray} containing the track selection for each renderer. */ @@ -48,7 +49,9 @@ public final class TrackSelectorResult { * TrackSelector#onSelectionActivated(Object)} should the selection be activated. */ public TrackSelectorResult( - RendererConfiguration[] rendererConfigurations, TrackSelection[] selections, Object info) { + @NullableType RendererConfiguration[] rendererConfigurations, + @NullableType TrackSelection[] selections, + Object info) { this.rendererConfigurations = rendererConfigurations; this.selections = new TrackSelectionArray(selections); this.info = info; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ui/AspectRatioFrameLayout.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ui/AspectRatioFrameLayout.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java index bdc467999..2575f058b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ui/AspectRatioFrameLayout.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.ui; +package com.google.android.exoplayer2.ui; import android.content.Context; import android.graphics.Matrix; @@ -106,10 +106,6 @@ public class AspectRatioFrameLayout extends FrameLayout { aspectRatioUpdateDispatcher = new AspectRatioUpdateDispatcher(); } - public boolean isDrawingReady() { - return drawingReady; - } - /** * Sets the aspect ratio that this view should satisfy. * @@ -166,6 +162,10 @@ public class AspectRatioFrameLayout extends FrameLayout { return rotation; } + public boolean isDrawingReady() { + return drawingReady; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocation.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocation.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java index ea21f31f9..f5aa81f32 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocation.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; /** * An allocation within a byte array. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocator.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocator.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocator.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocator.java index 3162b571e..17b7dfd6e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Allocator.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Allocator.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; /** * A source of allocations. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/AssetDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/AssetDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java index 69bc1b852..e151a4b17 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/AssetDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java @@ -13,20 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.content.Context; import android.content.res.AssetManager; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; -/** - * A {@link DataSource} for reading from a local asset. - */ -public final class AssetDataSource implements DataSource { +/** A {@link DataSource} for reading from a local asset. */ +public final class AssetDataSource extends BaseDataSource { /** * Thrown when an {@link IOException} is encountered reading a local asset. @@ -40,10 +39,9 @@ public final class AssetDataSource implements DataSource { } private final AssetManager assetManager; - private final TransferListener listener; - private Uri uri; - private InputStream inputStream; + private @Nullable Uri uri; + private @Nullable InputStream inputStream; private long bytesRemaining; private boolean opened; @@ -58,9 +56,12 @@ public final class AssetDataSource implements DataSource { * @param context A context. * @param listener An optional listener. */ - public AssetDataSource(Context context, TransferListener listener) { + public AssetDataSource(Context context, @Nullable TransferListener listener) { + super(/* isNetwork= */ false); this.assetManager = context.getAssets(); - this.listener = listener; + if (listener != null) { + addTransferListener(listener); + } } @Override @@ -73,6 +74,7 @@ public final class AssetDataSource implements DataSource { } else if (path.startsWith("/")) { path = path.substring(1); } + transferInitializing(dataSpec); inputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM); long skipped = inputStream.skip(dataSpec.position); if (skipped < dataSpec.position) { @@ -96,9 +98,7 @@ public final class AssetDataSource implements DataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return bytesRemaining; } @@ -129,14 +129,12 @@ public final class AssetDataSource implements DataSource { if (bytesRemaining != C.LENGTH_UNSET) { bytesRemaining -= bytesRead; } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } + bytesTransferred(bytesRead); return bytesRead; } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @@ -153,9 +151,7 @@ public final class AssetDataSource implements DataSource { inputStream = null; if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/BandwidthMeter.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java similarity index 64% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/BandwidthMeter.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java index e2a4cdde8..470937f02 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/BandwidthMeter.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BandwidthMeter.java @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; + +import android.os.Handler; +import android.support.annotation.Nullable; /** * Provides estimates of the currently available bandwidth. @@ -40,4 +43,26 @@ public interface BandwidthMeter { /** Returns the estimated bandwidth in bits/sec. */ long getBitrateEstimate(); + + /** + * Returns the {@link TransferListener} that this instance uses to gather bandwidth information + * from data transfers. May be null, if no transfer listener is used. + */ + @Nullable + TransferListener getTransferListener(); + + /** + * Adds an {@link EventListener} to be informed of bandwidth samples. + * + * @param eventHandler A handler for events. + * @param eventListener A listener of events. + */ + void addEventListener(Handler eventHandler, EventListener eventListener); + + /** + * Removes an {@link EventListener}. + * + * @param eventListener The listener to be removed. + */ + void removeEventListener(EventListener eventListener); } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BaseDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BaseDataSource.java new file mode 100755 index 000000000..6fd473dbf --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/BaseDataSource.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.Assertions; +import java.util.ArrayList; + +/** + * Base {@link DataSource} implementation to keep a list of {@link TransferListener}s. + * + *

    Subclasses must call {@link #transferInitializing(DataSpec)}, {@link + * #transferStarted(DataSpec)}, {@link #bytesTransferred(int)}, and {@link #transferEnded()} to + * inform listeners of data transfers. + */ +public abstract class BaseDataSource implements DataSource { + + private final boolean isNetwork; + private final ArrayList listeners; + + private @Nullable DataSpec dataSpec; + + /** + * Creates base data source. + * + * @param isNetwork Whether the data source loads data through a network. + */ + protected BaseDataSource(boolean isNetwork) { + this.isNetwork = isNetwork; + this.listeners = new ArrayList<>(/* initialCapacity= */ 1); + } + + @Override + public final void addTransferListener(TransferListener transferListener) { + listeners.add(transferListener); + } + + /** + * Notifies listeners that data transfer for the specified {@link DataSpec} is being initialized. + * + * @param dataSpec {@link DataSpec} describing the data for initializing transfer. + */ + protected final void transferInitializing(DataSpec dataSpec) { + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onTransferInitializing(/* source= */ this, dataSpec, isNetwork); + } + } + + /** + * Notifies listeners that data transfer for the specified {@link DataSpec} started. + * + * @param dataSpec {@link DataSpec} describing the data being transferred. + */ + protected final void transferStarted(DataSpec dataSpec) { + this.dataSpec = dataSpec; + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onTransferStart(/* source= */ this, dataSpec, isNetwork); + } + } + + /** + * Notifies listeners that bytes were transferred. + * + * @param bytesTransferred The number of bytes transferred since the previous call to this method + * (or if the first call, since the transfer was started). + */ + protected final void bytesTransferred(int bytesTransferred) { + DataSpec dataSpec = Assertions.checkNotNull(this.dataSpec); + for (int i = 0; i < listeners.size(); i++) { + listeners + .get(i) + .onBytesTransferred(/* source= */ this, dataSpec, isNetwork, bytesTransferred); + } + } + + /** Notifies listeners that a transfer ended. */ + protected final void transferEnded() { + DataSpec dataSpec = Assertions.checkNotNull(this.dataSpec); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onTransferEnd(/* source= */ this, dataSpec, isNetwork); + } + this.dataSpec = null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSink.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSink.java index 71c10bef1..4017c1f02 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSink.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java similarity index 76% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java index 19ed36c4c..16637b405 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ByteArrayDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ByteArrayDataSource.java @@ -13,28 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; -/** - * A {@link DataSource} for reading from a byte array. - */ -public final class ByteArrayDataSource implements DataSource { +/** A {@link DataSource} for reading from a byte array. */ +public final class ByteArrayDataSource extends BaseDataSource { private final byte[] data; - private Uri uri; + private @Nullable Uri uri; private int readPosition; private int bytesRemaining; + private boolean opened; /** * @param data The data to be read. */ public ByteArrayDataSource(byte[] data) { + super(/* isNetwork= */ false); Assertions.checkNotNull(data); Assertions.checkArgument(data.length > 0); this.data = data; @@ -43,6 +44,7 @@ public final class ByteArrayDataSource implements DataSource { @Override public long open(DataSpec dataSpec) throws IOException { uri = dataSpec.uri; + transferInitializing(dataSpec); readPosition = (int) dataSpec.position; bytesRemaining = (int) ((dataSpec.length == C.LENGTH_UNSET) ? (data.length - dataSpec.position) : dataSpec.length); @@ -50,6 +52,8 @@ public final class ByteArrayDataSource implements DataSource { throw new IOException("Unsatisfiable range: [" + readPosition + ", " + dataSpec.length + "], length: " + data.length); } + opened = true; + transferStarted(dataSpec); return bytesRemaining; } @@ -65,16 +69,21 @@ public final class ByteArrayDataSource implements DataSource { System.arraycopy(data, readPosition, buffer, offset, readLength); readPosition += readLength; bytesRemaining -= readLength; + bytesTransferred(readLength); return readLength; } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @Override public void close() throws IOException { + if (opened) { + opened = false; + transferEnded(); + } uri = null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ContentDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ContentDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index 0d62c4a38..0f75c68eb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ContentDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -13,23 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.channels.FileChannel; -/** - * A {@link DataSource} for reading from a content URI. - */ -public final class ContentDataSource implements DataSource { +/** A {@link DataSource} for reading from a content URI. */ +public final class ContentDataSource extends BaseDataSource { /** * Thrown when an {@link IOException} is encountered reading from a content URI. @@ -43,11 +42,10 @@ public final class ContentDataSource implements DataSource { } private final ContentResolver resolver; - private final TransferListener listener; - private Uri uri; - private AssetFileDescriptor assetFileDescriptor; - private FileInputStream inputStream; + private @Nullable Uri uri; + private @Nullable AssetFileDescriptor assetFileDescriptor; + private @Nullable FileInputStream inputStream; private long bytesRemaining; private boolean opened; @@ -62,15 +60,19 @@ public final class ContentDataSource implements DataSource { * @param context A context. * @param listener An optional listener. */ - public ContentDataSource(Context context, TransferListener listener) { + public ContentDataSource(Context context, @Nullable TransferListener listener) { + super(/* isNetwork= */ false); this.resolver = context.getContentResolver(); - this.listener = listener; + if (listener != null) { + addTransferListener(listener); + } } @Override public long open(DataSpec dataSpec) throws ContentDataSourceException { try { uri = dataSpec.uri; + transferInitializing(dataSpec); assetFileDescriptor = resolver.openAssetFileDescriptor(uri, "r"); if (assetFileDescriptor == null) { throw new FileNotFoundException("Could not open file descriptor for: " + uri); @@ -102,9 +104,7 @@ public final class ContentDataSource implements DataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return bytesRemaining; } @@ -136,14 +136,12 @@ public final class ContentDataSource implements DataSource { if (bytesRemaining != C.LENGTH_UNSET) { bytesRemaining -= bytesRead; } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } + bytesTransferred(bytesRead); return bytesRead; } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @@ -168,9 +166,7 @@ public final class ContentDataSource implements DataSource { assetFileDescriptor = null; if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSchemeDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java similarity index 72% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSchemeDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java index 27d5fc269..5a2f5d153 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSchemeDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java @@ -13,36 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; +import android.support.annotation.Nullable; import android.util.Base64; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.net.URLDecoder; -/** - * A {@link DataSource} for reading data URLs, as defined by RFC 2397. - */ -public final class DataSchemeDataSource implements DataSource { +/** A {@link DataSource} for reading data URLs, as defined by RFC 2397. */ +public final class DataSchemeDataSource extends BaseDataSource { public static final String SCHEME_DATA = "data"; - private DataSpec dataSpec; + private @Nullable DataSpec dataSpec; private int bytesRead; - private byte[] data; + private @Nullable byte[] data; + + public DataSchemeDataSource() { + super(/* isNetwork= */ false); + } @Override public long open(DataSpec dataSpec) throws IOException { + transferInitializing(dataSpec); this.dataSpec = dataSpec; Uri uri = dataSpec.uri; String scheme = uri.getScheme(); if (!SCHEME_DATA.equals(scheme)) { throw new ParserException("Unsupported scheme: " + scheme); } - String[] uriParts = uri.getSchemeSpecificPart().split(","); - if (uriParts.length > 2) { + String[] uriParts = Util.split(uri.getSchemeSpecificPart(), ","); + if (uriParts.length != 2) { throw new ParserException("Unexpected URI format: " + uri); } String dataString = uriParts[1]; @@ -56,6 +61,7 @@ public final class DataSchemeDataSource implements DataSource { // TODO: Add support for other charsets. data = URLDecoder.decode(dataString, C.ASCII_NAME).getBytes(); } + transferStarted(dataSpec); return data.length; } @@ -71,18 +77,22 @@ public final class DataSchemeDataSource implements DataSource { readLength = Math.min(readLength, remainingBytes); System.arraycopy(data, bytesRead, buffer, offset, readLength); bytesRead += readLength; + bytesTransferred(readLength); return readLength; } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return dataSpec != null ? dataSpec.uri : null; } @Override public void close() throws IOException { + if (data != null) { + data = null; + transferEnded(); + } dataSpec = null; - data = null; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSink.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSink.java index 2faeb88ef..4973bb71e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSink.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java index 29bc7f1a2..b3bb34e34 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; /** * A component from which streams of data can be read. @@ -34,7 +37,15 @@ public interface DataSource { * Creates a {@link DataSource} instance. */ DataSource createDataSource(); + } + /** + * Adds a {@link TransferListener} to listen to data transfers. This method is not thread-safe. + * + * @param transferListener A {@link TransferListener}. + */ + default void addTransferListener(TransferListener transferListener) { + // TODO: Make non-default once all DataSources implement this method. } /** @@ -82,6 +93,14 @@ public interface DataSource { */ @Nullable Uri getUri(); + /** + * When the source is open, returns the response headers associated with the last {@link #open} + * call. Otherwise, returns an empty map. + */ + default Map> getResponseHeaders() { + return Collections.emptyMap(); + } + /** * Closes the source. *

    @@ -91,5 +110,4 @@ public interface DataSource { * @throws IOException If an error occurs closing the source. */ void close() throws IOException; - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceException.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceException.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceException.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceException.java index 80e768047..e6b3ae270 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceException.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceInputStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceInputStream.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceInputStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceInputStream.java index 2771e8541..2f2075f35 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSourceInputStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSourceInputStream.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.support.annotation.NonNull; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.io.InputStream; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSpec.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSpec.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index f2821c70f..ad7a9d014 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DataSpec.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultAllocator.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultAllocator.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultAllocator.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultAllocator.java index 7e0210baf..d9bd5873f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultAllocator.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultAllocator.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultBandwidthMeter.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java similarity index 70% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultBandwidthMeter.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java index 9714fa26a..6e0fba27a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultBandwidthMeter.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.os.Handler; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Clock; -import org.telegram.messenger.exoplayer2.util.SlidingPercentile; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.EventDispatcher; +import com.google.android.exoplayer2.util.SlidingPercentile; /** - * Estimates bandwidth by listening to data transfers. The bandwidth estimate is calculated using - * a {@link SlidingPercentile} and is updated each time a transfer ends. + * Estimates bandwidth by listening to data transfers. The bandwidth estimate is calculated using a + * {@link SlidingPercentile} and is updated each time a transfer ends. */ -public final class DefaultBandwidthMeter implements BandwidthMeter, TransferListener { +public final class DefaultBandwidthMeter implements BandwidthMeter, TransferListener { /** Default initial bitrate estimate in bits per second. */ public static final long DEFAULT_INITIAL_BITRATE_ESTIMATE = 1_000_000; @@ -105,16 +106,19 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList * @return A bandwidth meter with the configured properties. */ public DefaultBandwidthMeter build() { - return new DefaultBandwidthMeter( - eventHandler, eventListener, initialBitrateEstimate, slidingWindowMaxWeight, clock); + DefaultBandwidthMeter bandwidthMeter = + new DefaultBandwidthMeter(initialBitrateEstimate, slidingWindowMaxWeight, clock); + if (eventHandler != null && eventListener != null) { + bandwidthMeter.addEventListener(eventHandler, eventListener); + } + return bandwidthMeter; } } private static final int ELAPSED_MILLIS_FOR_ESTIMATE = 2000; private static final int BYTES_TRANSFERRED_FOR_ESTIMATE = 512 * 1024; - private final @Nullable Handler eventHandler; - private final @Nullable EventListener eventListener; + private final EventDispatcher eventDispatcher; private final SlidingPercentile slidingPercentile; private final Clock clock; @@ -128,39 +132,32 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList /** Creates a bandwidth meter with default parameters. */ public DefaultBandwidthMeter() { - this( - /* eventHandler= */ null, - /* eventListener= */ null, - DEFAULT_INITIAL_BITRATE_ESTIMATE, - DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, - Clock.DEFAULT); + this(DEFAULT_INITIAL_BITRATE_ESTIMATE, DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, Clock.DEFAULT); } /** @deprecated Use {@link Builder} instead. */ @Deprecated public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener) { - this( - eventHandler, - eventListener, - DEFAULT_INITIAL_BITRATE_ESTIMATE, - DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, - Clock.DEFAULT); + this(DEFAULT_INITIAL_BITRATE_ESTIMATE, DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, Clock.DEFAULT); + if (eventHandler != null && eventListener != null) { + addEventListener(eventHandler, eventListener); + } } /** @deprecated Use {@link Builder} instead. */ @Deprecated public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener, int maxWeight) { - this(eventHandler, eventListener, DEFAULT_INITIAL_BITRATE_ESTIMATE, maxWeight, Clock.DEFAULT); + this(DEFAULT_INITIAL_BITRATE_ESTIMATE, maxWeight, Clock.DEFAULT); + if (eventHandler != null && eventListener != null) { + addEventListener(eventHandler, eventListener); + } } private DefaultBandwidthMeter( - @Nullable Handler eventHandler, - @Nullable EventListener eventListener, long initialBitrateEstimate, int maxWeight, Clock clock) { - this.eventHandler = eventHandler; - this.eventListener = eventListener; + this.eventDispatcher = new EventDispatcher<>(); this.slidingPercentile = new SlidingPercentile(maxWeight); this.clock = clock; bitrateEstimate = initialBitrateEstimate; @@ -172,7 +169,31 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList } @Override - public synchronized void onTransferStart(Object source, DataSpec dataSpec) { + public @Nullable TransferListener getTransferListener() { + return this; + } + + @Override + public void addEventListener(Handler eventHandler, EventListener eventListener) { + eventDispatcher.addListener(eventHandler, eventListener); + } + + @Override + public void removeEventListener(EventListener eventListener) { + eventDispatcher.removeListener(eventListener); + } + + @Override + public void onTransferInitializing(DataSource source, DataSpec dataSpec, boolean isNetwork) { + // Do nothing. + } + + @Override + public synchronized void onTransferStart( + DataSource source, DataSpec dataSpec, boolean isNetwork) { + if (!isNetwork) { + return; + } if (streamCount == 0) { sampleStartTimeMs = clock.elapsedRealtime(); } @@ -180,12 +201,19 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList } @Override - public synchronized void onBytesTransferred(Object source, int bytes) { + public synchronized void onBytesTransferred( + DataSource source, DataSpec dataSpec, boolean isNetwork, int bytes) { + if (!isNetwork) { + return; + } sampleBytesTransferred += bytes; } @Override - public synchronized void onTransferEnd(Object source) { + public synchronized void onTransferEnd(DataSource source, DataSpec dataSpec, boolean isNetwork) { + if (!isNetwork) { + return; + } Assertions.checkState(streamCount > 0); long nowMs = clock.elapsedRealtime(); int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs); @@ -206,14 +234,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList sampleBytesTransferred = 0; } - private void notifyBandwidthSample(final int elapsedMs, final long bytes, final long bitrate) { - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onBandwidthSample(elapsedMs, bytes, bitrate); - } - }); - } + private void notifyBandwidthSample(int elapsedMs, long bytes, long bitrate) { + eventDispatcher.dispatch(listener -> listener.onBandwidthSample(elapsedMs, bytes, bitrate)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java similarity index 69% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java index f3efb1fb4..cb9bb6817 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java @@ -13,14 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.content.Context; import android.net.Uri; +import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * A {@link DataSource} that supports multiple URI schemes. The supported schemes are: @@ -53,19 +57,18 @@ public final class DefaultDataSource implements DataSource { private static final String SCHEME_RAW = RawResourceDataSource.RAW_RESOURCE_SCHEME; private final Context context; - private final TransferListener listener; - + private final List transferListeners; private final DataSource baseDataSource; // Lazily initialized. - private DataSource fileDataSource; - private DataSource assetDataSource; - private DataSource contentDataSource; - private DataSource rtmpDataSource; - private DataSource dataSchemeDataSource; - private DataSource rawResourceDataSource; + private @Nullable DataSource fileDataSource; + private @Nullable DataSource assetDataSource; + private @Nullable DataSource contentDataSource; + private @Nullable DataSource rtmpDataSource; + private @Nullable DataSource dataSchemeDataSource; + private @Nullable DataSource rawResourceDataSource; - private DataSource dataSource; + private @Nullable DataSource dataSource; /** * Constructs a new instance, optionally configured to follow cross-protocol redirects. @@ -76,8 +79,11 @@ public final class DefaultDataSource implements DataSource { * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled when fetching remote data. */ - public DefaultDataSource(Context context, TransferListener listener, - String userAgent, boolean allowCrossProtocolRedirects) { + public DefaultDataSource( + Context context, + @Nullable TransferListener listener, + String userAgent, + boolean allowCrossProtocolRedirects) { this(context, listener, userAgent, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, allowCrossProtocolRedirects); } @@ -90,13 +96,17 @@ public final class DefaultDataSource implements DataSource { * @param userAgent The User-Agent string that should be used when requesting remote data. * @param connectTimeoutMillis The connection timeout that should be used when requesting remote * data, in milliseconds. A timeout of zero is interpreted as an infinite timeout. - * @param readTimeoutMillis The read timeout that should be used when requesting remote data, - * in milliseconds. A timeout of zero is interpreted as an infinite timeout. + * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in + * milliseconds. A timeout of zero is interpreted as an infinite timeout. * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled when fetching remote data. */ - public DefaultDataSource(Context context, TransferListener listener, - String userAgent, int connectTimeoutMillis, int readTimeoutMillis, + public DefaultDataSource( + Context context, + @Nullable TransferListener listener, + String userAgent, + int connectTimeoutMillis, + int readTimeoutMillis, boolean allowCrossProtocolRedirects) { this(context, listener, new DefaultHttpDataSource(userAgent, null, listener, connectTimeoutMillis, @@ -112,11 +122,26 @@ public final class DefaultDataSource implements DataSource { * @param baseDataSource A {@link DataSource} to use for URI schemes other than file, asset and * content. This {@link DataSource} should normally support at least http(s). */ - public DefaultDataSource(Context context, TransferListener listener, - DataSource baseDataSource) { + public DefaultDataSource( + Context context, @Nullable TransferListener listener, DataSource baseDataSource) { this.context = context.getApplicationContext(); - this.listener = listener; this.baseDataSource = Assertions.checkNotNull(baseDataSource); + transferListeners = new ArrayList<>(); + if (listener != null) { + transferListeners.add(listener); + } + } + + @Override + public void addTransferListener(TransferListener transferListener) { + baseDataSource.addTransferListener(transferListener); + transferListeners.add(transferListener); + maybeAddListenerToDataSource(fileDataSource, transferListener); + maybeAddListenerToDataSource(assetDataSource, transferListener); + maybeAddListenerToDataSource(contentDataSource, transferListener); + maybeAddListenerToDataSource(rtmpDataSource, transferListener); + maybeAddListenerToDataSource(dataSchemeDataSource, transferListener); + maybeAddListenerToDataSource(rawResourceDataSource, transferListener); } @Override @@ -149,14 +174,21 @@ public final class DefaultDataSource implements DataSource { @Override public int read(byte[] buffer, int offset, int readLength) throws IOException { - return dataSource.read(buffer, offset, readLength); + return Assertions.checkNotNull(dataSource).read(buffer, offset, readLength); } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return dataSource == null ? null : dataSource.getUri(); } + @Override + public Map> getResponseHeaders() { + return dataSource == null + ? DataSource.super.getResponseHeaders() + : dataSource.getResponseHeaders(); + } + @Override public void close() throws IOException { if (dataSource != null) { @@ -170,21 +202,24 @@ public final class DefaultDataSource implements DataSource { private DataSource getFileDataSource() { if (fileDataSource == null) { - fileDataSource = new FileDataSource(listener); + fileDataSource = new FileDataSource(); + addListenersToDataSource(fileDataSource); } return fileDataSource; } private DataSource getAssetDataSource() { if (assetDataSource == null) { - assetDataSource = new AssetDataSource(context, listener); + assetDataSource = new AssetDataSource(context); + addListenersToDataSource(assetDataSource); } return assetDataSource; } private DataSource getContentDataSource() { if (contentDataSource == null) { - contentDataSource = new ContentDataSource(context, listener); + contentDataSource = new ContentDataSource(context); + addListenersToDataSource(contentDataSource); } return contentDataSource; } @@ -193,9 +228,10 @@ public final class DefaultDataSource implements DataSource { if (rtmpDataSource == null) { try { // LINT.IfChange - Class clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.rtmp.RtmpDataSource"); + Class clazz = Class.forName("com.google.android.exoplayer2.ext.rtmp.RtmpDataSource"); rtmpDataSource = (DataSource) clazz.getConstructor().newInstance(); // LINT.ThenChange(../../../../../../../../proguard-rules.txt) + addListenersToDataSource(rtmpDataSource); } catch (ClassNotFoundException e) { // Expected if the app was built without the RTMP extension. Log.w(TAG, "Attempting to play RTMP stream without depending on the RTMP extension"); @@ -213,14 +249,29 @@ public final class DefaultDataSource implements DataSource { private DataSource getDataSchemeDataSource() { if (dataSchemeDataSource == null) { dataSchemeDataSource = new DataSchemeDataSource(); + addListenersToDataSource(dataSchemeDataSource); } return dataSchemeDataSource; } private DataSource getRawResourceDataSource() { if (rawResourceDataSource == null) { - rawResourceDataSource = new RawResourceDataSource(context, listener); + rawResourceDataSource = new RawResourceDataSource(context); + addListenersToDataSource(rawResourceDataSource); } return rawResourceDataSource; } + + private void addListenersToDataSource(DataSource dataSource) { + for (int i = 0; i < transferListeners.size(); i++) { + dataSource.addTransferListener(transferListeners.get(i)); + } + } + + private void maybeAddListenerToDataSource( + @Nullable DataSource dataSource, TransferListener listener) { + if (dataSource != null) { + dataSource.addTransferListener(listener); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java similarity index 69% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java index 2c0e6683b..293ba7f17 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.content.Context; -import org.telegram.messenger.exoplayer2.upstream.DataSource.Factory; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.upstream.DataSource.Factory; /** * A {@link Factory} that produces {@link DefaultDataSource} instances that delegate to @@ -25,7 +26,7 @@ import org.telegram.messenger.exoplayer2.upstream.DataSource.Factory; public final class DefaultDataSourceFactory implements Factory { private final Context context; - private final TransferListener listener; + private final @Nullable TransferListener listener; private final DataSource.Factory baseDataSourceFactory; /** @@ -33,7 +34,7 @@ public final class DefaultDataSourceFactory implements Factory { * @param userAgent The User-Agent string that should be used. */ public DefaultDataSourceFactory(Context context, String userAgent) { - this(context, userAgent, null); + this(context, userAgent, /* listener= */ null); } /** @@ -41,11 +42,21 @@ public final class DefaultDataSourceFactory implements Factory { * @param userAgent The User-Agent string that should be used. * @param listener An optional listener. */ - public DefaultDataSourceFactory(Context context, String userAgent, - TransferListener listener) { + public DefaultDataSourceFactory( + Context context, String userAgent, @Nullable TransferListener listener) { this(context, listener, new DefaultHttpDataSourceFactory(userAgent, listener)); } + /** + * @param context A context. + * @param baseDataSourceFactory A {@link Factory} to be used to create a base {@link DataSource} + * for {@link DefaultDataSource}. + * @see DefaultDataSource#DefaultDataSource(Context, TransferListener, DataSource) + */ + public DefaultDataSourceFactory(Context context, DataSource.Factory baseDataSourceFactory) { + this(context, /* listener= */ null, baseDataSourceFactory); + } + /** * @param context A context. * @param listener An optional listener. @@ -53,7 +64,9 @@ public final class DefaultDataSourceFactory implements Factory { * for {@link DefaultDataSource}. * @see DefaultDataSource#DefaultDataSource(Context, TransferListener, DataSource) */ - public DefaultDataSourceFactory(Context context, TransferListener listener, + public DefaultDataSourceFactory( + Context context, + @Nullable TransferListener listener, DataSource.Factory baseDataSourceFactory) { this.context = context.getApplicationContext(); this.listener = listener; @@ -64,5 +77,4 @@ public final class DefaultDataSourceFactory implements Factory { public DefaultDataSource createDataSource() { return new DefaultDataSource(context, listener, baseDataSourceFactory.createDataSource()); } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java index 95afb3290..5192f8285 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Predicate; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Predicate; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -32,6 +33,7 @@ import java.net.HttpURLConnection; import java.net.NoRouteToHostException; import java.net.ProtocolException; import java.net.URL; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -40,13 +42,13 @@ import java.util.regex.Pattern; /** * An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}. - *

    - * By default this implementation will not follow cross-protocol redirects (i.e. redirects from - * HTTP to HTTPS or vice versa). Cross-protocol redirects can be enabled by using the - * {@link #DefaultHttpDataSource(String, Predicate, TransferListener, int, int, boolean, + * + *

    By default this implementation will not follow cross-protocol redirects (i.e. redirects from + * HTTP to HTTPS or vice versa). Cross-protocol redirects can be enabled by using the {@link + * #DefaultHttpDataSource(String, Predicate, TransferListener, int, int, boolean, * RequestProperties)} constructor and passing {@code true} as the second last argument. */ -public class DefaultHttpDataSource implements HttpDataSource { +public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSource { /** * The default connection timeout, in milliseconds. @@ -68,14 +70,13 @@ public class DefaultHttpDataSource implements HttpDataSource { private final int connectTimeoutMillis; private final int readTimeoutMillis; private final String userAgent; - private final Predicate contentTypePredicate; - private final RequestProperties defaultRequestProperties; + private final @Nullable Predicate contentTypePredicate; + private final @Nullable RequestProperties defaultRequestProperties; private final RequestProperties requestProperties; - private final TransferListener listener; - private DataSpec dataSpec; - private HttpURLConnection connection; - private InputStream inputStream; + private @Nullable DataSpec dataSpec; + private @Nullable HttpURLConnection connection; + private @Nullable InputStream inputStream; private boolean opened; private long bytesToSkip; @@ -87,22 +88,24 @@ public class DefaultHttpDataSource implements HttpDataSource { /** * @param userAgent The User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the - * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from - * {@link #open(DataSpec)}. + * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link + * #open(DataSpec)}. */ - public DefaultHttpDataSource(String userAgent, Predicate contentTypePredicate) { + public DefaultHttpDataSource(String userAgent, @Nullable Predicate contentTypePredicate) { this(userAgent, contentTypePredicate, null); } /** * @param userAgent The User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the - * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from - * {@link #open(DataSpec)}. + * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link + * #open(DataSpec)}. * @param listener An optional listener. */ - public DefaultHttpDataSource(String userAgent, Predicate contentTypePredicate, - TransferListener listener) { + public DefaultHttpDataSource( + String userAgent, + @Nullable Predicate contentTypePredicate, + @Nullable TransferListener listener) { this(userAgent, contentTypePredicate, listener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS); } @@ -110,16 +113,19 @@ public class DefaultHttpDataSource implements HttpDataSource { /** * @param userAgent The User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the - * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from - * {@link #open(DataSpec)}. + * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link + * #open(DataSpec)}. * @param listener An optional listener. * @param connectTimeoutMillis The connection timeout, in milliseconds. A timeout of zero is * interpreted as an infinite timeout. - * @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted - * as an infinite timeout. + * @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted as + * an infinite timeout. */ - public DefaultHttpDataSource(String userAgent, Predicate contentTypePredicate, - TransferListener listener, int connectTimeoutMillis, + public DefaultHttpDataSource( + String userAgent, + @Nullable Predicate contentTypePredicate, + @Nullable TransferListener listener, + int connectTimeoutMillis, int readTimeoutMillis) { this(userAgent, contentTypePredicate, listener, connectTimeoutMillis, readTimeoutMillis, false, null); @@ -128,41 +134,48 @@ public class DefaultHttpDataSource implements HttpDataSource { /** * @param userAgent The User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the - * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from - * {@link #open(DataSpec)}. + * predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link + * #open(DataSpec)}. * @param listener An optional listener. * @param connectTimeoutMillis The connection timeout, in milliseconds. A timeout of zero is - * interpreted as an infinite timeout. Pass {@link #DEFAULT_CONNECT_TIMEOUT_MILLIS} to use - * the default value. - * @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted - * as an infinite timeout. Pass {@link #DEFAULT_READ_TIMEOUT_MILLIS} to use the default value. + * interpreted as an infinite timeout. Pass {@link #DEFAULT_CONNECT_TIMEOUT_MILLIS} to use the + * default value. + * @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted as + * an infinite timeout. Pass {@link #DEFAULT_READ_TIMEOUT_MILLIS} to use the default value. * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled. - * @param defaultRequestProperties The default request properties to be sent to the server as - * HTTP headers or {@code null} if not required. + * @param defaultRequestProperties The default request properties to be sent to the server as HTTP + * headers or {@code null} if not required. */ - public DefaultHttpDataSource(String userAgent, Predicate contentTypePredicate, - TransferListener listener, int connectTimeoutMillis, - int readTimeoutMillis, boolean allowCrossProtocolRedirects, - RequestProperties defaultRequestProperties) { + public DefaultHttpDataSource( + String userAgent, + @Nullable Predicate contentTypePredicate, + @Nullable TransferListener listener, + int connectTimeoutMillis, + int readTimeoutMillis, + boolean allowCrossProtocolRedirects, + @Nullable RequestProperties defaultRequestProperties) { + super(/* isNetwork= */ true); this.userAgent = Assertions.checkNotEmpty(userAgent); this.contentTypePredicate = contentTypePredicate; - this.listener = listener; this.requestProperties = new RequestProperties(); this.connectTimeoutMillis = connectTimeoutMillis; this.readTimeoutMillis = readTimeoutMillis; this.allowCrossProtocolRedirects = allowCrossProtocolRedirects; this.defaultRequestProperties = defaultRequestProperties; + if (listener != null) { + addTransferListener(listener); + } } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return connection == null ? null : Uri.parse(connection.getURL().toString()); } @Override public Map> getResponseHeaders() { - return connection == null ? null : connection.getHeaderFields(); + return connection == null ? Collections.emptyMap() : connection.getHeaderFields(); } @Override @@ -188,6 +201,7 @@ public class DefaultHttpDataSource implements HttpDataSource { this.dataSpec = dataSpec; this.bytesRead = 0; this.bytesSkipped = 0; + transferInitializing(dataSpec); try { connection = makeConnection(dataSpec); } catch (IOException e) { @@ -253,9 +267,7 @@ public class DefaultHttpDataSource implements HttpDataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return bytesToRead; } @@ -286,9 +298,7 @@ public class DefaultHttpDataSource implements HttpDataSource { closeConnectionQuietly(); if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } } @@ -533,9 +543,7 @@ public class DefaultHttpDataSource implements HttpDataSource { throw new EOFException(); } bytesSkipped += read; - if (listener != null) { - listener.onBytesTransferred(this, read); - } + bytesTransferred(read); } // Release the shared skip buffer. @@ -578,9 +586,7 @@ public class DefaultHttpDataSource implements HttpDataSource { } bytesRead += read; - if (listener != null) { - listener.onBytesTransferred(this, read); - } + bytesTransferred(read); return read; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java similarity index 68% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java index de991cc31..aa0ac7b97 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DefaultHttpDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.BaseFactory; -import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.Factory; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; +import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; /** A {@link Factory} that produces {@link DefaultHttpDataSource} instances. */ public final class DefaultHttpDataSourceFactory extends BaseFactory { private final String userAgent; - private final TransferListener listener; + private final @Nullable TransferListener listener; private final int connectTimeoutMillis; private final int readTimeoutMillis; private final boolean allowCrossProtocolRedirects; @@ -49,12 +50,33 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * @param listener An optional listener. * @see #DefaultHttpDataSourceFactory(String, TransferListener, int, int, boolean) */ - public DefaultHttpDataSourceFactory( - String userAgent, TransferListener listener) { + public DefaultHttpDataSourceFactory(String userAgent, @Nullable TransferListener listener) { this(userAgent, listener, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false); } + /** + * @param userAgent The User-Agent string that should be used. + * @param connectTimeoutMillis The connection timeout that should be used when requesting remote + * data, in milliseconds. A timeout of zero is interpreted as an infinite timeout. + * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in + * milliseconds. A timeout of zero is interpreted as an infinite timeout. + * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP + * to HTTPS and vice versa) are enabled. + */ + public DefaultHttpDataSourceFactory( + String userAgent, + int connectTimeoutMillis, + int readTimeoutMillis, + boolean allowCrossProtocolRedirects) { + this( + userAgent, + /* listener= */ null, + connectTimeoutMillis, + readTimeoutMillis, + allowCrossProtocolRedirects); + } + /** * @param userAgent The User-Agent string that should be used. * @param listener An optional listener. @@ -65,9 +87,12 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled. */ - public DefaultHttpDataSourceFactory(String userAgent, - TransferListener listener, int connectTimeoutMillis, - int readTimeoutMillis, boolean allowCrossProtocolRedirects) { + public DefaultHttpDataSourceFactory( + String userAgent, + @Nullable TransferListener listener, + int connectTimeoutMillis, + int readTimeoutMillis, + boolean allowCrossProtocolRedirects) { this.userAgent = userAgent; this.listener = listener; this.connectTimeoutMillis = connectTimeoutMillis; @@ -81,5 +106,4 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { return new DefaultHttpDataSource(userAgent, null, listener, connectTimeoutMillis, readTimeoutMillis, allowCrossProtocolRedirects, defaultRequestProperties); } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DummyDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DummyDataSource.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DummyDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DummyDataSource.java index 0bd220fd8..fa3e14f1c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/DummyDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/DummyDataSource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java index d5318868a..b765e06dd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.IOException; import java.io.RandomAccessFile; -/** - * A {@link DataSource} for reading local files. - */ -public final class FileDataSource implements DataSource { +/** A {@link DataSource} for reading local files. */ +public final class FileDataSource extends BaseDataSource { /** * Thrown when IOException is encountered during local file read operation. @@ -37,10 +36,8 @@ public final class FileDataSource implements DataSource { } - private final TransferListener listener; - - private RandomAccessFile file; - private Uri uri; + private @Nullable RandomAccessFile file; + private @Nullable Uri uri; private long bytesRemaining; private boolean opened; @@ -48,17 +45,19 @@ public final class FileDataSource implements DataSource { this(null); } - /** - * @param listener An optional listener. - */ - public FileDataSource(TransferListener listener) { - this.listener = listener; + /** @param listener An optional listener. */ + public FileDataSource(@Nullable TransferListener listener) { + super(/* isNetwork= */ false); + if (listener != null) { + addTransferListener(listener); + } } @Override public long open(DataSpec dataSpec) throws FileDataSourceException { try { uri = dataSpec.uri; + transferInitializing(dataSpec); file = new RandomAccessFile(dataSpec.uri.getPath(), "r"); file.seek(dataSpec.position); bytesRemaining = dataSpec.length == C.LENGTH_UNSET ? file.length() - dataSpec.position @@ -71,9 +70,7 @@ public final class FileDataSource implements DataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return bytesRemaining; } @@ -94,9 +91,7 @@ public final class FileDataSource implements DataSource { if (bytesRead > 0) { bytesRemaining -= bytesRead; - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } + bytesTransferred(bytesRead); } return bytesRead; @@ -104,7 +99,7 @@ public final class FileDataSource implements DataSource { } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @@ -121,9 +116,7 @@ public final class FileDataSource implements DataSource { file = null; if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSourceFactory.java similarity index 81% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSourceFactory.java index fde7e94b4..f69adeb8c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/FileDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/FileDataSourceFactory.java @@ -13,20 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; + +import android.support.annotation.Nullable; /** * A {@link DataSource.Factory} that produces {@link FileDataSource}. */ public final class FileDataSourceFactory implements DataSource.Factory { - private final TransferListener listener; + private final @Nullable TransferListener listener; public FileDataSourceFactory() { this(null); } - public FileDataSourceFactory(TransferListener listener) { + public FileDataSourceFactory(@Nullable TransferListener listener) { this.listener = listener; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/HttpDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/HttpDataSource.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/HttpDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/HttpDataSource.java index 9fbd024a8..71a0e6826 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/HttpDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/HttpDataSource.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.support.annotation.IntDef; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.util.Predicate; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Predicate; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -341,10 +341,6 @@ public interface HttpDataSource extends DataSource { */ void clearAllRequestProperties(); - /** - * Returns the headers provided in the response, or {@code null} if response headers are - * unavailable. - */ + @Override Map> getResponseHeaders(); - } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java new file mode 100755 index 000000000..8d6c0b9cf --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil; +import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; +import com.google.android.exoplayer2.upstream.Loader.Callback; +import com.google.android.exoplayer2.upstream.Loader.Loadable; +import java.io.IOException; + +/** + * Defines how errors encountered by {@link Loader Loaders} are handled. + * + *

    Loader clients may blacklist a resource when a load error occurs. Blacklisting works around + * load errors by loading an alternative resource. Clients do not try blacklisting when a resource + * does not have an alternative. When a resource does have valid alternatives, {@link + * #getBlacklistDurationMsFor(T, long, IOException, int)} defines whether the resource should be + * blacklisted. Blacklisting will succeed if any of the alternatives is not in the black list. + * + *

    When blacklisting does not take place, {@link #getRetryDelayMsFor(T, long, IOException, int)} + * defines whether the load is retried. Errors whose load is not retried are propagated. Load errors + * whose load is retried are propagated according to {@link + * #getMinimumLoadableRetryCount(Loadable)}. + * + * @param The type of the object being loaded. + */ +public interface LoadErrorHandlingPolicy { + + /** The default minimum number of times to retry loading data prior to propagating the error. */ + int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; + + /** Default implementation of {@link LoadErrorHandlingPolicy}. */ + LoadErrorHandlingPolicy DEFAULT = + new LoadErrorHandlingPolicy() { + + /** + * Blacklists resources whose load error was an {@link InvalidResponseCodeException} with + * response code HTTP 404 or 410. The duration of the blacklisting is {@link + * ChunkedTrackBlacklistUtil#DEFAULT_TRACK_BLACKLIST_MS}. + */ + @Override + public long getBlacklistDurationMsFor( + Loadable loadable, long loadDurationMs, IOException exception, int errorCount) { + if (exception instanceof InvalidResponseCodeException) { + int responseCode = ((InvalidResponseCodeException) exception).responseCode; + return responseCode == 404 // HTTP 404 Not Found. + || responseCode == 410 // HTTP 410 Gone. + ? ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS + : C.TIME_UNSET; + } + return C.TIME_UNSET; + } + + /** + * Retries for any exception that is not a subclass of {@link ParserException}. The retry + * delay is calculated as {@code Math.min((errorCount - 1) * 1000, 5000)}. + */ + @Override + public long getRetryDelayMsFor( + Loadable loadable, long loadDurationMs, IOException exception, int errorCount) { + return exception instanceof ParserException + ? C.TIME_UNSET + : Math.min((errorCount - 1) * 1000, 5000); + } + + /** Returns {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. */ + @Override + public int getMinimumLoadableRetryCount(Loadable loadable) { + return DEFAULT_MIN_LOADABLE_RETRY_COUNT; + } + }; + + /** Returns {@link #DEFAULT}. */ + static LoadErrorHandlingPolicy getDefault() { + @SuppressWarnings("unchecked") // Safe contravariant cast. + LoadErrorHandlingPolicy policy = (LoadErrorHandlingPolicy) DEFAULT; + return policy; + } + + /** + * Returns the number of milliseconds for which a resource associated to a provided load error + * should be blacklisted, or {@link C#TIME_UNSET} if the resource should not be blacklisted. + * + * @param loadable The loadable whose load failed. + * @param loadDurationMs The duration in milliseconds of the load up to the point at which the + * error occurred, including any previous attempts. + * @param exception The load error. + * @param errorCount The number of errors this load has encountered, including this one. + * @return The blacklist duration in milliseconds, or {@link C#TIME_UNSET} if the resource should + * not be blacklisted. + */ + long getBlacklistDurationMsFor( + T loadable, long loadDurationMs, IOException exception, int errorCount); + + /** + * Returns the number of milliseconds to wait before attempting the load again, or {@link + * C#TIME_UNSET} if the error is fatal and should not be retried. + * + *

    {@link Loader} clients may ignore the retry delay returned by this method in order to wait + * for a specific event before retrying. However, the load is retried if and only if this method + * does not return {@link C#TIME_UNSET}. + * + * @param loadable The loadable whose load failed. + * @param loadDurationMs The duration in milliseconds of the load up to the point at which the + * error occurred, including any previous attempts. + * @param exception The load error. + * @param errorCount The number of errors this load has encountered, including this one. + * @return The number of milliseconds to wait before attempting the load again, or {@link + * C#TIME_UNSET} if the error is fatal and should not be retried. + */ + long getRetryDelayMsFor(T loadable, long loadDurationMs, IOException exception, int errorCount); + + /** + * Returns the minimum number of times to retry a load in the case of a load error, before + * propagating the error. + * + * @param loadable The loadable to load. + * @return The minimum number of times to retry a load in the case of a load error, before + * propagating the error. + * @see Loader#startLoading(Loadable, Callback, int) + */ + int getMinimumLoadableRetryCount(T loadable); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Loader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Loader.java similarity index 70% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Loader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Loader.java index 5df09abae..e284310f9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/Loader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/Loader.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.annotation.SuppressLint; import android.os.Handler; @@ -23,9 +23,10 @@ import android.os.SystemClock; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.TraceUtil; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.TraceUtil; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -57,11 +58,6 @@ public final class Loader implements LoaderErrorThrower { */ void cancelLoad(); - /** - * Returns whether the load has been canceled. - */ - boolean isLoadCanceled(); - /** * Performs the load, returning on completion or cancellation. * @@ -79,27 +75,29 @@ public final class Loader implements LoaderErrorThrower { /** * Called when a load has completed. - *

    - * Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting and - * this callback being called. + * + *

    Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting + * and this callback being called. * * @param loadable The loadable whose load has completed. * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load ended. - * @param loadDurationMs The duration of the load. + * @param loadDurationMs The duration in milliseconds of the load since {@link #startLoading} + * was called. */ void onLoadCompleted(T loadable, long elapsedRealtimeMs, long loadDurationMs); /** * Called when a load has been canceled. - *

    - * Note: If the {@link Loader} has not been released then there is guaranteed to be a memory - * barrier between {@link Loadable#load()} exiting and this callback being called. If the - * {@link Loader} has been released then this callback may be called before - * {@link Loadable#load()} exits. + * + *

    Note: If the {@link Loader} has not been released then there is guaranteed to be a memory + * barrier between {@link Loadable#load()} exiting and this callback being called. If the {@link + * Loader} has been released then this callback may be called before {@link Loadable#load()} + * exits. * * @param loadable The loadable whose load has been canceled. * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load was canceled. - * @param loadDurationMs The duration of the load up to the point at which it was canceled. + * @param loadDurationMs The duration in milliseconds of the load since {@link #startLoading} + * was called up to the point at which it was canceled. * @param released True if the load was canceled because the {@link Loader} was released. False * otherwise. */ @@ -113,14 +111,16 @@ public final class Loader implements LoaderErrorThrower { * * @param loadable The loadable whose load has encountered an error. * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the error occurred. - * @param loadDurationMs The duration of the load up to the point at which the error occurred. + * @param loadDurationMs The duration in milliseconds of the load since {@link #startLoading} + * was called up to the point at which the error occurred. * @param error The load error. - * @return The desired retry action. One of {@link Loader#RETRY}, {@link - * Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY} and {@link - * Loader#DONT_RETRY_FATAL}. + * @param errorCount The number of errors this load has encountered, including this one. + * @return The desired error handling action. One of {@link Loader#RETRY}, {@link + * Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY}, {@link + * Loader#DONT_RETRY_FATAL} or a retry action created by {@link #createRetryAction}. */ - @RetryAction - int onLoadError(T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error); + LoadErrorAction onLoadError( + T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error, int errorCount); } /** @@ -135,15 +135,56 @@ public final class Loader implements LoaderErrorThrower { } - /** Actions that can be taken in response to a load error. */ + /** Types of action that can be taken in response to a load error. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({RETRY, RETRY_RESET_ERROR_COUNT, DONT_RETRY, DONT_RETRY_FATAL}) - public @interface RetryAction {} + @IntDef({ + ACTION_TYPE_RETRY, + ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT, + ACTION_TYPE_DONT_RETRY, + ACTION_TYPE_DONT_RETRY_FATAL + }) + private @interface RetryActionType {} - public static final int RETRY = 0; - public static final int RETRY_RESET_ERROR_COUNT = 1; - public static final int DONT_RETRY = 2; - public static final int DONT_RETRY_FATAL = 3; + private static final int ACTION_TYPE_RETRY = 0; + private static final int ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT = 1; + private static final int ACTION_TYPE_DONT_RETRY = 2; + private static final int ACTION_TYPE_DONT_RETRY_FATAL = 3; + + /** Retries the load using the default delay. */ + public static final LoadErrorAction RETRY = + createRetryAction(/* resetErrorCount= */ false, C.TIME_UNSET); + /** Retries the load using the default delay and resets the error count. */ + public static final LoadErrorAction RETRY_RESET_ERROR_COUNT = + createRetryAction(/* resetErrorCount= */ true, C.TIME_UNSET); + /** Discards the failed loading task and ignores any errors that have occurred. */ + public static final LoadErrorAction DONT_RETRY = + new LoadErrorAction(ACTION_TYPE_DONT_RETRY, C.TIME_UNSET); + /** + * Discards the failed load. The next call to {@link #maybeThrowError()} will throw the last load + * error. + */ + public static final LoadErrorAction DONT_RETRY_FATAL = + new LoadErrorAction(ACTION_TYPE_DONT_RETRY_FATAL, C.TIME_UNSET); + + /** + * Action that can be taken in response to {@link Callback#onLoadError(Loadable, long, long, + * IOException, int)}. + */ + public static final class LoadErrorAction { + + private final @RetryActionType int type; + private final long retryDelayMillis; + + private LoadErrorAction(@RetryActionType int type, long retryDelayMillis) { + this.type = type; + this.retryDelayMillis = retryDelayMillis; + } + + /** Returns whether this is a retry action. */ + public boolean isRetry() { + return type == ACTION_TYPE_RETRY || type == ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT; + } + } private final ExecutorService downloadExecutorService; @@ -157,6 +198,19 @@ public final class Loader implements LoaderErrorThrower { this.downloadExecutorService = Util.newSingleThreadExecutor(threadName); } + /** + * Creates a {@link LoadErrorAction} for retrying with the given parameters. + * + * @param resetErrorCount Whether the previous error count should be set to zero. + * @param retryDelayMillis The number of milliseconds to wait before retrying. + * @return A {@link LoadErrorAction} for retrying with the given parameters. + */ + public static LoadErrorAction createRetryAction(boolean resetErrorCount, long retryDelayMillis) { + return new LoadErrorAction( + resetErrorCount ? ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT : ACTION_TYPE_RETRY, + retryDelayMillis); + } + /** * Starts loading a {@link Loadable}. * @@ -250,15 +304,17 @@ public final class Loader implements LoaderErrorThrower { private static final int MSG_IO_EXCEPTION = 3; private static final int MSG_FATAL_ERROR = 4; - private final T loadable; - private final Loader.Callback callback; public final int defaultMinRetryCount; + + private final T loadable; private final long startTimeMs; + private @Nullable Loader.Callback callback; private IOException currentError; private int errorCount; private volatile Thread executorThread; + private volatile boolean canceled; private volatile boolean released; public LoadTask(Looper looper, T loadable, Loader.Callback callback, @@ -295,6 +351,7 @@ public final class Loader implements LoaderErrorThrower { sendEmptyMessage(MSG_CANCEL); } } else { + canceled = true; loadable.cancelLoad(); if (executorThread != null) { executorThread.interrupt(); @@ -304,6 +361,11 @@ public final class Loader implements LoaderErrorThrower { finish(); long nowMs = SystemClock.elapsedRealtime(); callback.onLoadCanceled(loadable, nowMs, nowMs - startTimeMs, true); + // If loading, this task will be referenced from a GC root (the loading thread) until + // cancellation completes. The time taken for cancellation to complete depends on the + // implementation of the Loadable that the task is loading. We null the callback reference + // here so that it doesn't prevent garbage collection whilst cancellation is ongoing. + callback = null; } } @@ -311,7 +373,7 @@ public final class Loader implements LoaderErrorThrower { public void run() { try { executorThread = Thread.currentThread(); - if (!loadable.isLoadCanceled()) { + if (!canceled) { TraceUtil.beginSection("load:" + loadable.getClass().getSimpleName()); try { loadable.load(); @@ -328,7 +390,7 @@ public final class Loader implements LoaderErrorThrower { } } catch (InterruptedException e) { // The load was canceled. - Assertions.checkState(loadable.isLoadCanceled()); + Assertions.checkState(canceled); if (!released) { sendEmptyMessage(MSG_END_OF_SOURCE); } @@ -373,7 +435,7 @@ public final class Loader implements LoaderErrorThrower { finish(); long nowMs = SystemClock.elapsedRealtime(); long durationMs = nowMs - startTimeMs; - if (loadable.isLoadCanceled()) { + if (canceled) { callback.onLoadCanceled(loadable, nowMs, durationMs, false); return; } @@ -392,12 +454,19 @@ public final class Loader implements LoaderErrorThrower { break; case MSG_IO_EXCEPTION: currentError = (IOException) msg.obj; - int retryAction = callback.onLoadError(loadable, nowMs, durationMs, currentError); - if (retryAction == DONT_RETRY_FATAL) { + errorCount++; + LoadErrorAction action = + callback.onLoadError(loadable, nowMs, durationMs, currentError, errorCount); + if (action.type == ACTION_TYPE_DONT_RETRY_FATAL) { fatalError = currentError; - } else if (retryAction != DONT_RETRY) { - errorCount = retryAction == RETRY_RESET_ERROR_COUNT ? 1 : errorCount + 1; - start(getRetryDelayMillis()); + } else if (action.type != ACTION_TYPE_DONT_RETRY) { + if (action.type == ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT) { + errorCount = 1; + } + start( + action.retryDelayMillis != C.TIME_UNSET + ? action.retryDelayMillis + : getRetryDelayMillis()); } break; default: diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/LoaderErrorThrower.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoaderErrorThrower.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/LoaderErrorThrower.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoaderErrorThrower.java index f990b8501..4f9e9fa5e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/LoaderErrorThrower.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/LoaderErrorThrower.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; -import org.telegram.messenger.exoplayer2.upstream.Loader.Loadable; +import com.google.android.exoplayer2.upstream.Loader.Loadable; import java.io.IOException; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ParsingLoadable.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java similarity index 70% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ParsingLoadable.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java index 203d90e44..17d479daa 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/ParsingLoadable.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.upstream.Loader.Loadable; -import org.telegram.messenger.exoplayer2.util.Util; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.upstream.Loader.Loadable; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.io.InputStream; @@ -52,16 +54,17 @@ public final class ParsingLoadable implements Loadable { * Loads a single parsable object. * * @param dataSource The {@link DataSource} through which the object should be read. + * @param parser The {@link Parser} to parse the object from the response. * @param uri The {@link Uri} of the object to read. + * @param type The type of the data. One of the {@link C}{@code DATA_TYPE_*} constants. * @return The parsed object * @throws IOException Thrown if there is an error while loading or parsing. */ - public static T load(DataSource dataSource, Parser parser, Uri uri) + public static T load(DataSource dataSource, Parser parser, Uri uri, int type) throws IOException { - ParsingLoadable loadable = - new ParsingLoadable<>(dataSource, uri, C.DATA_TYPE_UNKNOWN, parser); + ParsingLoadable loadable = new ParsingLoadable<>(dataSource, uri, type, parser); loadable.load(); - return loadable.getResult(); + return Assertions.checkNotNull(loadable.getResult()); } /** @@ -74,12 +77,10 @@ public final class ParsingLoadable implements Loadable { */ public final int type; - private final DataSource dataSource; + private final StatsDataSource dataSource; private final Parser parser; - private volatile T result; - private volatile boolean isCanceled; - private volatile long bytesLoaded; + private volatile @Nullable T result; /** * @param dataSource A {@link DataSource} to use when loading the data. @@ -103,51 +104,50 @@ public final class ParsingLoadable implements Loadable { */ public ParsingLoadable(DataSource dataSource, DataSpec dataSpec, int type, Parser parser) { - this.dataSource = dataSource; + this.dataSource = new StatsDataSource(dataSource); this.dataSpec = dataSpec; this.type = type; this.parser = parser; } - /** - * Returns the loaded object, or null if an object has not been loaded. - */ - public final T getResult() { + /** Returns the loaded object, or null if an object has not been loaded. */ + public final @Nullable T getResult() { return result; } /** * Returns the number of bytes loaded. In the case that the network response was compressed, the - * value returned is the size of the data after decompression. - * - * @return The number of bytes loaded. + * value returned is the size of the data after decompression. Must only be called after + * the load completed, failed, or was canceled. */ public long bytesLoaded() { - return bytesLoaded; + return dataSource.getBytesRead(); + } + + /** + * Returns the {@link Uri} from which data was read. If redirection occurred, this is the + * redirected uri. Must only be called after the load completed, failed, or was canceled. + */ + public Uri getUri() { + return dataSource.getLastOpenedUri(); } @Override public final void cancelLoad() { - // We don't actually cancel anything, but we need to record the cancellation so that - // isLoadCanceled can return the correct value. - isCanceled = true; - } - - @Override - public final boolean isLoadCanceled() { - return isCanceled; + // Do nothing. } @Override public final void load() throws IOException { + // We always load from the beginning, so reset bytesRead to 0. + dataSource.resetBytesRead(); DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); try { inputStream.open(); - result = parser.parse(dataSource.getUri(), inputStream); + Uri dataSourceUri = Assertions.checkNotNull(dataSource.getUri()); + result = parser.parse(dataSourceUri, inputStream); } finally { - bytesLoaded = inputStream.bytesRead(); Util.closeQuietly(inputStream); } } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java index 2dfb5c524..9f9a3f9a9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.PriorityTaskManager; import java.io.IOException; +import java.util.List; +import java.util.Map; /** * A {@link DataSource} that can be used as part of a task registered with a @@ -51,6 +53,11 @@ public final class PriorityDataSource implements DataSource { this.priority = priority; } + @Override + public void addTransferListener(TransferListener transferListener) { + upstream.addTransferListener(transferListener); + } + @Override public long open(DataSpec dataSpec) throws IOException { priorityTaskManager.proceedOrThrow(priority); @@ -68,6 +75,11 @@ public final class PriorityDataSource implements DataSource { return upstream.getUri(); } + @Override + public Map> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + @Override public void close() throws IOException { upstream.close(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSourceFactory.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSourceFactory.java index 055a80216..daad41a9a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/PriorityDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSourceFactory.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; -import org.telegram.messenger.exoplayer2.upstream.DataSource.Factory; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.upstream.DataSource.Factory; +import com.google.android.exoplayer2.util.PriorityTaskManager; /** * A {@link DataSource.Factory} that produces {@link PriorityDataSource} instances. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/RawResourceDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java similarity index 86% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/RawResourceDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java index 9602b6f5d..9ca7273d4 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/RawResourceDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/RawResourceDataSource.java @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.net.Uri; +import android.support.annotation.Nullable; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.FileInputStream; import java.io.IOException; @@ -28,12 +29,12 @@ import java.io.InputStream; /** * A {@link DataSource} for reading a raw resource inside the APK. - *

    - * URIs supported by this source are of the form {@code rawresource:///rawResourceId}, where + * + *

    URIs supported by this source are of the form {@code rawresource:///rawResourceId}, where * rawResourceId is the integer identifier of a raw resource. {@link #buildRawResourceUri(int)} can * be used to build {@link Uri}s in this format. */ -public final class RawResourceDataSource implements DataSource { +public final class RawResourceDataSource extends BaseDataSource { /** * Thrown when an {@link IOException} is encountered reading from a raw resource. @@ -62,11 +63,10 @@ public final class RawResourceDataSource implements DataSource { public static final String RAW_RESOURCE_SCHEME = "rawresource"; private final Resources resources; - private final TransferListener listener; - private Uri uri; - private AssetFileDescriptor assetFileDescriptor; - private InputStream inputStream; + private @Nullable Uri uri; + private @Nullable AssetFileDescriptor assetFileDescriptor; + private @Nullable InputStream inputStream; private long bytesRemaining; private boolean opened; @@ -81,10 +81,12 @@ public final class RawResourceDataSource implements DataSource { * @param context A context. * @param listener An optional listener. */ - public RawResourceDataSource(Context context, - TransferListener listener) { + public RawResourceDataSource(Context context, @Nullable TransferListener listener) { + super(/* isNetwork= */ false); this.resources = context.getResources(); - this.listener = listener; + if (listener != null) { + addTransferListener(listener); + } } @Override @@ -102,6 +104,7 @@ public final class RawResourceDataSource implements DataSource { throw new RawResourceDataSourceException("Resource identifier must be an integer."); } + transferInitializing(dataSpec); assetFileDescriptor = resources.openRawResourceFd(resourceId); inputStream = new FileInputStream(assetFileDescriptor.getFileDescriptor()); inputStream.skip(assetFileDescriptor.getStartOffset()); @@ -124,9 +127,7 @@ public final class RawResourceDataSource implements DataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return bytesRemaining; } @@ -158,14 +159,12 @@ public final class RawResourceDataSource implements DataSource { if (bytesRemaining != C.LENGTH_UNSET) { bytesRemaining -= bytesRead; } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } + bytesTransferred(bytesRead); return bytesRead; } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @@ -190,9 +189,7 @@ public final class RawResourceDataSource implements DataSource { assetFileDescriptor = null; if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } } diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java new file mode 100755 index 000000000..04b29b531 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream; + +import android.net.Uri; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * {@link DataSource} wrapper which keeps track of bytes transferred, redirected uris, and response + * headers. + */ +public final class StatsDataSource implements DataSource { + + private final DataSource dataSource; + + private long bytesRead; + private Uri lastOpenedUri; + private Map> lastResponseHeaders; + + /** + * Creates the stats data source. + * + * @param dataSource The wrapped {@link DataSource}. + */ + public StatsDataSource(DataSource dataSource) { + this.dataSource = Assertions.checkNotNull(dataSource); + lastOpenedUri = Uri.EMPTY; + lastResponseHeaders = Collections.emptyMap(); + } + + /** Resets the number of bytes read as returned from {@link #getBytesRead()} to zero. */ + public void resetBytesRead() { + bytesRead = 0; + } + + /** Returns the total number of bytes that have been read from the data source. */ + public long getBytesRead() { + return bytesRead; + } + + /** + * Returns the {@link Uri} associated with the last {@link #open(DataSpec)} call. If redirection + * occurred, this is the redirected uri. + */ + public Uri getLastOpenedUri() { + return lastOpenedUri; + } + + /** Returns the response headers associated with the last {@link #open(DataSpec)} call. */ + public Map> getLastResponseHeaders() { + return lastResponseHeaders; + } + + @Override + public void addTransferListener(TransferListener transferListener) { + dataSource.addTransferListener(transferListener); + } + + @Override + public long open(DataSpec dataSpec) throws IOException { + // Reassign defaults in case dataSource.open throws an exception. + lastOpenedUri = dataSpec.uri; + lastResponseHeaders = Collections.emptyMap(); + long availableBytes = dataSource.open(dataSpec); + lastOpenedUri = Assertions.checkNotNull(getUri()); + lastResponseHeaders = getResponseHeaders(); + return availableBytes; + } + + @Override + public int read(byte[] buffer, int offset, int readLength) throws IOException { + int bytesRead = dataSource.read(buffer, offset, readLength); + if (bytesRead != C.RESULT_END_OF_INPUT) { + this.bytesRead += bytesRead; + } + return bytesRead; + } + + @Override + public @Nullable Uri getUri() { + return dataSource.getUri(); + } + + @Override + public Map> getResponseHeaders() { + return dataSource.getResponseHeaders(); + } + + @Override + public void close() throws IOException { + dataSource.close(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TeeDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TeeDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java index 1d4cd09fc..3c021b0b7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TeeDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; +import java.util.List; +import java.util.Map; /** * Tees data into a {@link DataSink} as the data is read. @@ -40,6 +43,11 @@ public final class TeeDataSource implements DataSource { this.dataSink = Assertions.checkNotNull(dataSink); } + @Override + public void addTransferListener(TransferListener transferListener) { + upstream.addTransferListener(transferListener); + } + @Override public long open(DataSpec dataSpec) throws IOException { bytesRemaining = upstream.open(dataSpec); @@ -48,14 +56,7 @@ public final class TeeDataSource implements DataSource { } if (dataSpec.length == C.LENGTH_UNSET && bytesRemaining != C.LENGTH_UNSET) { // Reconstruct dataSpec in order to provide the resolved length to the sink. - dataSpec = - new DataSpec( - dataSpec.uri, - dataSpec.absoluteStreamPosition, - dataSpec.position, - bytesRemaining, - dataSpec.key, - dataSpec.flags); + dataSpec = dataSpec.subrange(0, bytesRemaining); } dataSinkNeedsClosing = true; dataSink.open(dataSpec); @@ -79,10 +80,15 @@ public final class TeeDataSource implements DataSource { } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return upstream.getUri(); } + @Override + public Map> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + @Override public void close() throws IOException { try { diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TransferListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TransferListener.java new file mode 100755 index 000000000..a8971e71a --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/TransferListener.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream; + +/** + * A listener of data transfer events. + * + *

    A transfer usually progresses through multiple steps: + * + *

      + *
    1. Initializing the underlying resource (e.g. opening a HTTP connection). {@link + * #onTransferInitializing(DataSource, DataSpec, boolean)} is called before the initialization + * starts. + *
    2. Starting the transfer after successfully initializing the resource. {@link + * #onTransferStart(DataSource, DataSpec, boolean)} is called. Note that this only happens if + * the initialization was successful. + *
    3. Transferring data. {@link #onBytesTransferred(DataSource, DataSpec, boolean, int)} is + * called frequently during the transfer to indicate progress. + *
    4. Closing the transfer and the underlying resource. {@link #onTransferEnd(DataSource, + * DataSpec, boolean)} is called. Note that each {@link #onTransferStart(DataSource, DataSpec, + * boolean)} will have exactly one corresponding call to {@link #onTransferEnd(DataSource, + * DataSpec, boolean)}. + *
    + */ +public interface TransferListener { + + /** + * Called when a transfer is being initialized. + * + * @param source The source performing the transfer. + * @param dataSpec Describes the data for which the transfer is initialized. + * @param isNetwork Whether the data is transferred through a network. + */ + void onTransferInitializing(DataSource source, DataSpec dataSpec, boolean isNetwork); + + /** + * Called when a transfer starts. + * + * @param source The source performing the transfer. + * @param dataSpec Describes the data being transferred. + * @param isNetwork Whether the data is transferred through a network. + */ + void onTransferStart(DataSource source, DataSpec dataSpec, boolean isNetwork); + + /** + * Called incrementally during a transfer. + * + * @param source The source performing the transfer. + * @param dataSpec Describes the data being transferred. + * @param isNetwork Whether the data is transferred through a network. + * @param bytesTransferred The number of bytes transferred since the previous call to this method + */ + void onBytesTransferred( + DataSource source, DataSpec dataSpec, boolean isNetwork, int bytesTransferred); + + /** + * Called when a transfer ends. + * + * @param source The source performing the transfer. + * @param dataSpec Describes the data being transferred. + * @param isNetwork Whether the data is transferred through a network. + */ + void onTransferEnd(DataSource source, DataSpec dataSpec, boolean isNetwork); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/UdpDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/UdpDataSource.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/UdpDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/UdpDataSource.java index c607bbe6b..c7efe316b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/UdpDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/UdpDataSource.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -25,10 +26,8 @@ import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.SocketException; -/** - * A UDP {@link DataSource}. - */ -public final class UdpDataSource implements DataSource { +/** A UDP {@link DataSource}. */ +public final class UdpDataSource extends BaseDataSource { /** * Thrown when an error is encountered when trying to read from a {@link UdpDataSource}. @@ -51,24 +50,21 @@ public final class UdpDataSource implements DataSource { */ public static final int DEAFULT_SOCKET_TIMEOUT_MILLIS = 8 * 1000; - private final TransferListener listener; private final int socketTimeoutMillis; private final byte[] packetBuffer; private final DatagramPacket packet; - private Uri uri; - private DatagramSocket socket; - private MulticastSocket multicastSocket; - private InetAddress address; - private InetSocketAddress socketAddress; + private @Nullable Uri uri; + private @Nullable DatagramSocket socket; + private @Nullable MulticastSocket multicastSocket; + private @Nullable InetAddress address; + private @Nullable InetSocketAddress socketAddress; private boolean opened; private int packetRemaining; - /** - * @param listener An optional listener. - */ - public UdpDataSource(TransferListener listener) { + /** @param listener An optional listener. */ + public UdpDataSource(@Nullable TransferListener listener) { this(listener, DEFAULT_MAX_PACKET_SIZE); } @@ -76,7 +72,7 @@ public final class UdpDataSource implements DataSource { * @param listener An optional listener. * @param maxPacketSize The maximum datagram packet size, in bytes. */ - public UdpDataSource(TransferListener listener, int maxPacketSize) { + public UdpDataSource(@Nullable TransferListener listener, int maxPacketSize) { this(listener, maxPacketSize, DEAFULT_SOCKET_TIMEOUT_MILLIS); } @@ -86,12 +82,15 @@ public final class UdpDataSource implements DataSource { * @param socketTimeoutMillis The socket timeout in milliseconds. A timeout of zero is interpreted * as an infinite timeout. */ - public UdpDataSource(TransferListener listener, int maxPacketSize, - int socketTimeoutMillis) { - this.listener = listener; + public UdpDataSource( + @Nullable TransferListener listener, int maxPacketSize, int socketTimeoutMillis) { + super(/* isNetwork= */ true); this.socketTimeoutMillis = socketTimeoutMillis; packetBuffer = new byte[maxPacketSize]; packet = new DatagramPacket(packetBuffer, 0, maxPacketSize); + if (listener != null) { + addTransferListener(listener); + } } @Override @@ -99,7 +98,7 @@ public final class UdpDataSource implements DataSource { uri = dataSpec.uri; String host = uri.getHost(); int port = uri.getPort(); - + transferInitializing(dataSpec); try { address = InetAddress.getByName(host); socketAddress = new InetSocketAddress(address, port); @@ -121,9 +120,7 @@ public final class UdpDataSource implements DataSource { } opened = true; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } + transferStarted(dataSpec); return C.LENGTH_UNSET; } @@ -141,9 +138,7 @@ public final class UdpDataSource implements DataSource { throw new UdpDataSourceException(e); } packetRemaining = packet.getLength(); - if (listener != null) { - listener.onBytesTransferred(this, packetRemaining); - } + bytesTransferred(packetRemaining); } int packetOffset = packet.getLength() - packetRemaining; @@ -154,7 +149,7 @@ public final class UdpDataSource implements DataSource { } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return uri; } @@ -178,9 +173,7 @@ public final class UdpDataSource implements DataSource { packetRemaining = 0; if (opened) { opened = false; - if (listener != null) { - listener.onTransferEnd(this); - } + transferEnded(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/Cache.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/Cache.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java index 9ab29ee79..584939fdc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/Cache.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -237,11 +237,11 @@ public interface Cache { /** * Returns the content length for the given key if one set, or {@link - * org.telegram.messenger.exoplayer2.C#LENGTH_UNSET} otherwise. + * com.google.android.exoplayer2.C#LENGTH_UNSET} otherwise. * * @param key The cache key for the data. * @return The content length for the given key if one set, or {@link - * org.telegram.messenger.exoplayer2.C#LENGTH_UNSET} otherwise. + * com.google.android.exoplayer2.C#LENGTH_UNSET} otherwise. */ long getContentLength(String key); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java similarity index 93% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java index c5d0cab88..8d310015f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSink; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache.CacheException; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.ReusableBufferedOutputStream; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.ReusableBufferedOutputStream; +import com.google.android.exoplayer2.util.Util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSinkFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSinkFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java index ea98c6b42..0b9ab6650 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSinkFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; -import org.telegram.messenger.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSink; /** * A {@link DataSink.Factory} that produces {@link CacheDataSink}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java similarity index 80% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java index 2385aeafc..04c099014 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java @@ -13,25 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.net.Uri; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSink; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSourceException; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.FileDataSource; -import org.telegram.messenger.exoplayer2.upstream.TeeDataSource; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache.CacheException; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSourceException; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.FileDataSource; +import com.google.android.exoplayer2.upstream.TeeDataSource; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; +import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.io.InterruptedIOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Map; /** * A {@link DataSource} that reads and writes a {@link Cache}. Requests are fulfilled from the cache @@ -52,8 +54,6 @@ public final class CacheDataSource implements DataSource { */ public static final long DEFAULT_MAX_CACHE_FILE_SIZE = 2 * 1024 * 1024; - private static final String TAG = "CacheDataSource"; - /** * Flags controlling the cache's behavior. */ @@ -120,23 +120,24 @@ public final class CacheDataSource implements DataSource { private final Cache cache; private final DataSource cacheReadDataSource; - private final DataSource cacheWriteDataSource; + private final @Nullable DataSource cacheWriteDataSource; private final DataSource upstreamDataSource; + private final CacheKeyFactory cacheKeyFactory; @Nullable private final EventListener eventListener; private final boolean blockOnCache; private final boolean ignoreCacheOnError; private final boolean ignoreCacheForUnsetLengthRequests; - private DataSource currentDataSource; + private @Nullable DataSource currentDataSource; private boolean currentDataSpecLengthUnset; - private Uri uri; - private Uri actualUri; + private @Nullable Uri uri; + private @Nullable Uri actualUri; private int flags; - private String key; + private @Nullable String key; private long readPosition; private long bytesRemaining; - private CacheSpan currentHoleSpan; + private @Nullable CacheSpan currentHoleSpan; private boolean seenCacheError; private boolean currentRequestIgnoresCache; private long totalCachedBytesRead; @@ -181,8 +182,13 @@ public final class CacheDataSource implements DataSource { */ public CacheDataSource(Cache cache, DataSource upstream, @Flags int flags, long maxCacheFileSize) { - this(cache, upstream, new FileDataSource(), new CacheDataSink(cache, maxCacheFileSize), - flags, null); + this( + cache, + upstream, + new FileDataSource(), + new CacheDataSink(cache, maxCacheFileSize), + flags, + /* eventListener= */ null); } /** @@ -201,8 +207,43 @@ public final class CacheDataSource implements DataSource { */ public CacheDataSource(Cache cache, DataSource upstream, DataSource cacheReadDataSource, DataSink cacheWriteDataSink, @Flags int flags, @Nullable EventListener eventListener) { + this( + cache, + upstream, + cacheReadDataSource, + cacheWriteDataSink, + flags, + eventListener, + /* cacheKeyFactory= */ null); + } + + /** + * Constructs an instance with arbitrary {@link DataSource} and {@link DataSink} instances for + * reading and writing the cache. One use of this constructor is to allow data to be transformed + * before it is written to disk. + * + * @param cache The cache. + * @param upstream A {@link DataSource} for reading data not in the cache. + * @param cacheReadDataSource A {@link DataSource} for reading data from the cache. + * @param cacheWriteDataSink A {@link DataSink} for writing data to the cache. If null, cache is + * accessed read-only. + * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE}, {@link #FLAG_IGNORE_CACHE_ON_ERROR} + * and {@link #FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS}, or 0. + * @param eventListener An optional {@link EventListener} to receive events. + * @param cacheKeyFactory An optional factory for cache keys. + */ + public CacheDataSource( + Cache cache, + DataSource upstream, + DataSource cacheReadDataSource, + DataSink cacheWriteDataSink, + @Flags int flags, + @Nullable EventListener eventListener, + @Nullable CacheKeyFactory cacheKeyFactory) { this.cache = cache; this.cacheReadDataSource = cacheReadDataSource; + this.cacheKeyFactory = + cacheKeyFactory != null ? cacheKeyFactory : CacheUtil.DEFAULT_CACHE_KEY_FACTORY; this.blockOnCache = (flags & FLAG_BLOCK_ON_CACHE) != 0; this.ignoreCacheOnError = (flags & FLAG_IGNORE_CACHE_ON_ERROR) != 0; this.ignoreCacheForUnsetLengthRequests = @@ -216,12 +257,18 @@ public final class CacheDataSource implements DataSource { this.eventListener = eventListener; } + @Override + public void addTransferListener(TransferListener transferListener) { + cacheReadDataSource.addTransferListener(transferListener); + upstreamDataSource.addTransferListener(transferListener); + } + @Override public long open(DataSpec dataSpec) throws IOException { try { - key = CacheUtil.getKey(dataSpec); + key = cacheKeyFactory.buildCacheKey(dataSpec); uri = dataSpec.uri; - actualUri = loadRedirectedUriOrReturnGivenUri(cache, key, uri); + actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri); flags = dataSpec.flags; readPosition = dataSpec.position; @@ -272,7 +319,7 @@ public final class CacheDataSource implements DataSource { bytesRemaining -= bytesRead; } } else if (currentDataSpecLengthUnset) { - setBytesRemainingAndMaybeStoreLength(0); + setNoBytesRemainingAndMaybeStoreLength(); } else if (bytesRemaining > 0 || bytesRemaining == C.LENGTH_UNSET) { closeCurrentSource(); openNextSource(false); @@ -281,7 +328,7 @@ public final class CacheDataSource implements DataSource { return bytesRead; } catch (IOException e) { if (currentDataSpecLengthUnset && isCausedByPositionOutOfRange(e)) { - setBytesRemainingAndMaybeStoreLength(0); + setNoBytesRemainingAndMaybeStoreLength(); return C.RESULT_END_OF_INPUT; } handleBeforeThrow(e); @@ -290,10 +337,18 @@ public final class CacheDataSource implements DataSource { } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return actualUri; } + @Override + public Map> getResponseHeaders() { + // TODO: Implement. + return isReadingFromUpstream() + ? upstreamDataSource.getResponseHeaders() + : DataSource.super.getResponseHeaders(); + } + @Override public void close() throws IOException { uri = null; @@ -402,46 +457,38 @@ public final class CacheDataSource implements DataSource { currentDataSource = nextDataSource; currentDataSpecLengthUnset = nextDataSpec.length == C.LENGTH_UNSET; long resolvedLength = nextDataSource.open(nextDataSpec); - if (currentDataSpecLengthUnset && resolvedLength != C.LENGTH_UNSET) { - setBytesRemainingAndMaybeStoreLength(resolvedLength); - } - // TODO find a way to store length and redirected uri in one metadata mutation. - maybeUpdateActualUriFieldAndRedirectedUriMetadata(); - } - private void maybeUpdateActualUriFieldAndRedirectedUriMetadata() { - if (!isReadingFromUpstream()) { - return; - } - actualUri = currentDataSource.getUri(); - maybeUpdateRedirectedUriMetadata(); - } - - private void maybeUpdateRedirectedUriMetadata() { - if (!isWritingToCache()) { - return; - } + // Update bytesRemaining, actualUri and (if writing to cache) the cache metadata. ContentMetadataMutations mutations = new ContentMetadataMutations(); - boolean isRedirected = !uri.equals(actualUri); - if (isRedirected) { - ContentMetadataInternal.setRedirectedUri(mutations, actualUri); - } else { - ContentMetadataInternal.removeRedirectedUri(mutations); + if (currentDataSpecLengthUnset && resolvedLength != C.LENGTH_UNSET) { + bytesRemaining = resolvedLength; + ContentMetadataInternal.setContentLength(mutations, readPosition + bytesRemaining); } - try { + if (isReadingFromUpstream()) { + actualUri = currentDataSource.getUri(); + boolean isRedirected = !uri.equals(actualUri); + if (isRedirected) { + ContentMetadataInternal.setRedirectedUri(mutations, actualUri); + } else { + ContentMetadataInternal.removeRedirectedUri(mutations); + } + } + if (isWritingToCache()) { cache.applyContentMetadataMutations(key, mutations); - } catch (CacheException e) { - String message = - "Couldn't update redirected URI. " - + "This might cause relative URIs get resolved incorrectly."; - Log.w(TAG, message, e); } } - private static Uri loadRedirectedUriOrReturnGivenUri(Cache cache, String key, Uri uri) { + private void setNoBytesRemainingAndMaybeStoreLength() throws IOException { + bytesRemaining = 0; + if (isWritingToCache()) { + cache.setContentLength(key, readPosition); + } + } + + private static Uri getRedirectedUriOrDefault(Cache cache, String key, Uri defaultUri) { ContentMetadata contentMetadata = cache.getContentMetadata(key); Uri redirectedUri = ContentMetadataInternal.getRedirectedUri(contentMetadata); - return redirectedUri == null ? uri : redirectedUri; + return redirectedUri == null ? defaultUri : redirectedUri; } private static boolean isCausedByPositionOutOfRange(IOException e) { @@ -458,13 +505,6 @@ public final class CacheDataSource implements DataSource { return false; } - private void setBytesRemainingAndMaybeStoreLength(long bytesRemaining) throws IOException { - this.bytesRemaining = bytesRemaining; - if (isWritingToCache()) { - cache.setContentLength(key, readPosition + bytesRemaining); - } - } - private boolean isReadingFromUpstream() { return !isReadingFromCache(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSourceFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSourceFactory.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java index beba2714c..f0285da27 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheDataSourceFactory.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; -import org.telegram.messenger.exoplayer2.upstream.DataSink; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSource.Factory; -import org.telegram.messenger.exoplayer2.upstream.FileDataSourceFactory; -import org.telegram.messenger.exoplayer2.upstream.cache.CacheDataSource.EventListener; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSource.Factory; +import com.google.android.exoplayer2.upstream.FileDataSourceFactory; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource.EventListener; /** * A {@link DataSource.Factory} that produces {@link CacheDataSource}. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheEvictor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheEvictor.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheEvictor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheEvictor.java index 1ad477635..8944b4503 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheEvictor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheEvictor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; /** * Evicts data from a {@link Cache}. Implementations should call {@link Cache#removeSpan(CacheSpan)} diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheKeyFactory.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheKeyFactory.java new file mode 100755 index 000000000..bfa404c07 --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheKeyFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream.cache; + +import com.google.android.exoplayer2.upstream.DataSpec; + +/** Factory for cache keys. */ +public interface CacheKeyFactory { + + /** + * Returns a cache key for the given {@link DataSpec}. + * + * @param dataSpec The data being cached. + */ + String buildCacheKey(DataSpec dataSpec); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheSpan.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheSpan.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java index 72b5314ef..2082740bb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheSpan.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.File; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java similarity index 84% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index a36f38aea..9052aceb9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CacheUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.PriorityTaskManager; +import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; import java.util.NavigableSet; @@ -54,6 +54,15 @@ public final class CacheUtil { /** Default buffer size to be used while caching. */ public static final int DEFAULT_BUFFER_SIZE_BYTES = 128 * 1024; + /** Default {@link CacheKeyFactory} that calls through to {@link #getKey}. */ + public static final CacheKeyFactory DEFAULT_CACHE_KEY_FACTORY = + new CacheKeyFactory() { + @Override + public String buildCacheKey(DataSpec dataSpec) { + return getKey(dataSpec); + } + }; + /** * Generates a cache key out of the given {@link Uri}. * @@ -129,11 +138,11 @@ public final class CacheUtil { cache, new CacheDataSource(cache, upstream), new byte[DEFAULT_BUFFER_SIZE_BYTES], - null, - 0, + /* priorityTaskManager= */ null, + /* priority= */ 0, counters, - null, - false); + isCanceled, + /* enableEOFException= */ false); } /** @@ -186,9 +195,7 @@ public final class CacheUtil { long start = dataSpec.absoluteStreamPosition; long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key); while (left != 0) { - if (isCanceled != null && isCanceled.get()) { - throw new InterruptedException(); - } + throwExceptionIfInterruptedOrCancelled(isCanceled); long blockLength = cache.getCachedLength(key, start, left != C.LENGTH_UNSET ? left : Long.MAX_VALUE); if (blockLength > 0) { @@ -196,8 +203,17 @@ public final class CacheUtil { } else { // There is a hole in the cache which is at least "-blockLength" long. blockLength = -blockLength; - long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer, - priorityTaskManager, priority, counters); + long read = + readAndDiscard( + dataSpec, + start, + blockLength, + dataSource, + buffer, + priorityTaskManager, + priority, + counters, + isCanceled); if (read < blockLength) { // Reached to the end of the data. if (enableEOFException && left != C.LENGTH_UNSET) { @@ -224,21 +240,28 @@ public final class CacheUtil { * caching. * @param priority The priority of this task. * @param counters Counters to be set during reading. + * @param isCanceled An optional flag that will interrupt caching if set to true. * @return Number of read bytes, or 0 if no data is available because the end of the opened range * has been reached. */ - private static long readAndDiscard(DataSpec dataSpec, long absoluteStreamPosition, long length, - DataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, int priority, - CachingCounters counters) throws IOException, InterruptedException { + private static long readAndDiscard( + DataSpec dataSpec, + long absoluteStreamPosition, + long length, + DataSource dataSource, + byte[] buffer, + PriorityTaskManager priorityTaskManager, + int priority, + CachingCounters counters, + AtomicBoolean isCanceled) + throws IOException, InterruptedException { while (true) { if (priorityTaskManager != null) { // Wait for any other thread with higher priority to finish its job. priorityTaskManager.proceed(priority); } try { - if (Thread.interrupted()) { - throw new InterruptedException(); - } + throwExceptionIfInterruptedOrCancelled(isCanceled); // Create a new dataSpec setting length to C.LENGTH_UNSET to prevent getting an error in // case the given length exceeds the end of input. dataSpec = new DataSpec(dataSpec.uri, dataSpec.postBody, absoluteStreamPosition, @@ -251,9 +274,7 @@ public final class CacheUtil { } long totalRead = 0; while (totalRead != length) { - if (Thread.interrupted()) { - throw new InterruptedException(); - } + throwExceptionIfInterruptedOrCancelled(isCanceled); int read = dataSource.read(buffer, 0, length != C.LENGTH_UNSET ? (int) Math.min(buffer.length, length - totalRead) : buffer.length); @@ -287,6 +308,13 @@ public final class CacheUtil { } } + private static void throwExceptionIfInterruptedOrCancelled(AtomicBoolean isCanceled) + throws InterruptedException { + if (Thread.interrupted() || (isCanceled != null && isCanceled.get())) { + throw new InterruptedException(); + } + } + private CacheUtil() {} } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContent.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContent.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java index e649bafc2..89835f31d 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContent.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache.CacheException; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; +import com.google.android.exoplayer2.util.Assertions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContentIndex.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContentIndex.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java index c850a44ae..3bcfac505 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedContentIndex.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.util.SparseArray; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache.CacheException; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.AtomicFile; -import org.telegram.messenger.exoplayer2.util.ReusableBufferedOutputStream; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.AtomicFile; +import com.google.android.exoplayer2.util.ReusableBufferedOutputStream; +import com.google.android.exoplayer2.util.Util; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedRegionTracker.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedRegionTracker.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedRegionTracker.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedRegionTracker.java index 29859a436..9455aed11 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/CachedRegionTracker.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedRegionTracker.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.NonNull; import android.util.Log; -import org.telegram.messenger.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.ChunkIndex; import java.util.Arrays; import java.util.Iterator; import java.util.NavigableSet; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadata.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadata.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadata.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadata.java index d28eabee6..aacd11f91 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadata.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadata.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; /** * Interface for an immutable snapshot of keyed metadata. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataInternal.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataInternal.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataInternal.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataInternal.java index b6b78cdb2..006501826 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataInternal.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataInternal.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.net.Uri; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** Helper classes to easily access and modify internal metadata values. */ -/*package*/ final class ContentMetadataInternal { +/* package */ final class ContentMetadataInternal { private static final String PREFIX = ContentMetadata.INTERNAL_METADATA_NAME_PREFIX; private static final String METADATA_NAME_REDIRECTED_URI = PREFIX + "redir"; @@ -59,4 +59,8 @@ import org.telegram.messenger.exoplayer2.C; public static void removeRedirectedUri(ContentMetadataMutations mutations) { mutations.remove(METADATA_NAME_REDIRECTED_URI); } + + private ContentMetadataInternal() { + // Prevent instantiation. + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataMutations.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataMutations.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataMutations.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataMutations.java index ad8a2aeaa..70154b030 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/ContentMetadataMutations.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadataMutations.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/DefaultContentMetadata.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/DefaultContentMetadata.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java index a11c596e4..cf63bcc4f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/DefaultContentMetadata.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -34,7 +34,7 @@ public final class DefaultContentMetadata implements ContentMetadata { /** An empty DefaultContentMetadata. */ public static final DefaultContentMetadata EMPTY = - new DefaultContentMetadata(Collections.emptyMap()); + new DefaultContentMetadata(Collections.emptyMap()); private static final int MAX_VALUE_LENGTH = 10 * 1024 * 1024; private int hashCode; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java index 9b0809286..79d23dd1b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/LeastRecentlyUsedCacheEvictor.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; -import org.telegram.messenger.exoplayer2.upstream.cache.Cache.CacheException; +import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; import java.util.Comparator; import java.util.TreeSet; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/NoOpCacheEvictor.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/NoOpCacheEvictor.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/NoOpCacheEvictor.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/NoOpCacheEvictor.java index 4e234fb4b..b0c8c7e08 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/NoOpCacheEvictor.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/NoOpCacheEvictor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; /** diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCache.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCache.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java index 5ec74bd79..7d2d5b79a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCache.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.os.ConditionVariable; import android.support.annotation.NonNull; import android.util.Log; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import java.io.File; import java.util.ArrayList; import java.util.HashMap; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCacheSpan.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCacheSpan.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java index 48da6e67b..e12d876ce 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/cache/SimpleCacheSpan.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.cache; +package com.google.android.exoplayer2.upstream.cache; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSink.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSink.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java index 86d686360..ccf9a5b3f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSink.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.crypto; +package com.google.android.exoplayer2.upstream.crypto; -import org.telegram.messenger.exoplayer2.upstream.DataSink; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSpec; import java.io.IOException; import javax.crypto.Cipher; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSource.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java similarity index 72% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSource.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java index 087aa727b..801c84dc5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesCipherDataSource.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java @@ -13,13 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.crypto; +package com.google.android.exoplayer2.upstream.crypto; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; +import java.util.List; +import java.util.Map; import javax.crypto.Cipher; /** @@ -30,13 +34,18 @@ public final class AesCipherDataSource implements DataSource { private final DataSource upstream; private final byte[] secretKey; - private AesFlushingCipher cipher; + private @Nullable AesFlushingCipher cipher; public AesCipherDataSource(byte[] secretKey, DataSource upstream) { this.upstream = upstream; this.secretKey = secretKey; } + @Override + public void addTransferListener(TransferListener transferListener) { + upstream.addTransferListener(transferListener); + } + @Override public long open(DataSpec dataSpec) throws IOException { long dataLength = upstream.open(dataSpec); @@ -59,15 +68,19 @@ public final class AesCipherDataSource implements DataSource { return read; } + @Override + public @Nullable Uri getUri() { + return upstream.getUri(); + } + + @Override + public Map> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + @Override public void close() throws IOException { cipher = null; upstream.close(); } - - @Override - public Uri getUri() { - return upstream.getUri(); - } - } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesFlushingCipher.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesFlushingCipher.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java index a386b7324..1721b1d8b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/AesFlushingCipher.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.crypto; +package com.google.android.exoplayer2.upstream.crypto; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -49,7 +50,9 @@ public final class AesFlushingCipher { flushedBlock = new byte[blockSize]; long counter = offset / blockSize; int startPadding = (int) (offset % blockSize); - cipher.init(mode, new SecretKeySpec(secretKey, cipher.getAlgorithm().split("/")[0]), + cipher.init( + mode, + new SecretKeySpec(secretKey, Util.splitAtFirst(cipher.getAlgorithm(), "/")[0]), new IvParameterSpec(getInitializationVector(nonce, counter))); if (startPadding != 0) { updateInPlace(new byte[startPadding], 0, startPadding); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/CryptoUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/CryptoUtil.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/CryptoUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/CryptoUtil.java index b05577b0b..ff8841fa9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/crypto/CryptoUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/upstream/crypto/CryptoUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.upstream.crypto; +package com.google.android.exoplayer2.upstream.crypto; /** * Utility functions for the crypto package. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Assertions.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Assertions.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Assertions.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Assertions.java index a25a73efa..c6ad5dfe5 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Assertions.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Assertions.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.os.Looper; import android.support.annotation.Nullable; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import org.checkerframework.checker.nullness.qual.EnsuresNonNull; /** * Provides methods for asserting the truth of expressions and properties. @@ -103,6 +104,8 @@ public final class Assertions { * @return The non-null reference that was validated. * @throws NullPointerException If {@code reference} is null. */ + @SuppressWarnings({"contracts.postcondition.not.satisfied", "return.type.incompatible"}) + @EnsuresNonNull({"#1"}) public static T checkNotNull(@Nullable T reference) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) { throw new NullPointerException(); @@ -120,6 +123,8 @@ public final class Assertions { * @return The non-null reference that was validated. * @throws NullPointerException If {@code reference} is null. */ + @SuppressWarnings({"contracts.postcondition.not.satisfied", "return.type.incompatible"}) + @EnsuresNonNull({"#1"}) public static T checkNotNull(@Nullable T reference, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) { throw new NullPointerException(String.valueOf(errorMessage)); @@ -134,6 +139,8 @@ public final class Assertions { * @return The non-null, non-empty string that was validated. * @throws IllegalArgumentException If {@code string} is null or 0-length. */ + @SuppressWarnings({"contracts.postcondition.not.satisfied", "return.type.incompatible"}) + @EnsuresNonNull({"#1"}) public static String checkNotEmpty(@Nullable String string) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) { throw new IllegalArgumentException(); @@ -150,6 +157,8 @@ public final class Assertions { * @return The non-null, non-empty string that was validated. * @throws IllegalArgumentException If {@code string} is null or 0-length. */ + @SuppressWarnings({"contracts.postcondition.not.satisfied", "return.type.incompatible"}) + @EnsuresNonNull({"#1"}) public static String checkNotEmpty(@Nullable String string, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) { throw new IllegalArgumentException(String.valueOf(errorMessage)); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/AtomicFile.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/AtomicFile.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/AtomicFile.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/AtomicFile.java index 090e519d9..b33fc2b92 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/AtomicFile.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/AtomicFile.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.support.annotation.NonNull; import android.util.Log; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Clock.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Clock.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Clock.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Clock.java index 9af9b3353..36fc3b1bf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Clock.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Clock.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.os.Handler; import android.os.Looper; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/CodecSpecificDataUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/CodecSpecificDataUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java index ff60d9ed7..e1ffa1024 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/CodecSpecificDataUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; +import android.support.annotation.Nullable; import android.util.Pair; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ParserException; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; import java.util.ArrayList; import java.util.List; @@ -221,8 +222,8 @@ public final class CodecSpecificDataUtil { /** * Splits an array of NAL units. - *

    - * If the input consists of NAL start code delimited units, then the returned array consists of + * + *

    If the input consists of NAL start code delimited units, then the returned array consists of * the split NAL units, each of which is still prefixed with the NAL start code. For any other * input, null is returned. * @@ -230,7 +231,7 @@ public final class CodecSpecificDataUtil { * @return The individual NAL units, or null if the input did not consist of NAL start code * delimited units. */ - public static byte[][] splitNalUnits(byte[] data) { + public static @Nullable byte[][] splitNalUnits(byte[] data) { if (!isNalStartCode(data, 0)) { // data does not consist of NAL start code delimited units. return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ColorParser.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ColorParser.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ColorParser.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ColorParser.java index 11f0dcc0f..54f52e0a1 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ColorParser.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ColorParser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.text.TextUtils; import java.util.HashMap; @@ -26,7 +26,7 @@ import java.util.regex.Pattern; * * @see WebVTT CSS Styling * @see Timed Text Markup Language 2 (TTML2) - 10.3.5 - **/ + */ public final class ColorParser { private static final String RGB = "rgb"; @@ -271,4 +271,7 @@ public final class ColorParser { COLOR_MAP.put("yellowgreen", 0xFF9ACD32); } + private ColorParser() { + // Prevent instantiation. + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ConditionVariable.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ConditionVariable.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ConditionVariable.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ConditionVariable.java index 18c535f4c..058a5d6dd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ConditionVariable.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ConditionVariable.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; /** * An interruptible condition variable whose {@link #open()} and {@link #close()} methods return diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EGLSurfaceTexture.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EGLSurfaceTexture.java similarity index 78% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EGLSurfaceTexture.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EGLSurfaceTexture.java index 941584bb0..7e831f051 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EGLSurfaceTexture.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EGLSurfaceTexture.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.annotation.TargetApi; import android.graphics.SurfaceTexture; @@ -33,6 +33,12 @@ import java.lang.annotation.RetentionPolicy; @TargetApi(17) public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableListener, Runnable { + /** Listener to be called when the texture image on {@link SurfaceTexture} has been updated. */ + public interface TextureImageListener { + /** Called when the {@link SurfaceTexture} receives a new frame from its image producer. */ + void onFrameAvailable(); + } + /** Secure mode to be used by the EGL surface and context. */ @Retention(RetentionPolicy.SOURCE) @IntDef({SECURE_MODE_NONE, SECURE_MODE_SURFACELESS_CONTEXT, SECURE_MODE_PROTECTED_PBUFFER}) @@ -45,6 +51,9 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL /** Creating a secure surface backed by a pixel buffer. */ public static final int SECURE_MODE_PROTECTED_PBUFFER = 2; + private static final int EGL_SURFACE_WIDTH = 1; + private static final int EGL_SURFACE_HEIGHT = 1; + private static final int[] EGL_CONFIG_ATTRIBUTES = new int[] { EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, @@ -69,6 +78,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL private final Handler handler; private final int[] textureIdHolder; + private final @Nullable TextureImageListener callback; private @Nullable EGLDisplay display; private @Nullable EGLContext context; @@ -82,7 +92,21 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL * looper. */ public EGLSurfaceTexture(Handler handler) { + this(handler, /* callback= */ null); + } + + /** + * @param handler The {@link Handler} that will be used to call {@link + * SurfaceTexture#updateTexImage()} to update images on the {@link SurfaceTexture}. Note that + * {@link #init(int)} has to be called on the same looper thread as the looper of the {@link + * Handler}. + * @param callback The {@link TextureImageListener} to be called when the texture image on {@link + * SurfaceTexture} has been updated. This callback will be called on the same handler thread + * as the {@code handler}. + */ + public EGLSurfaceTexture(Handler handler, @Nullable TextureImageListener callback) { this.handler = handler; + this.callback = callback; textureIdHolder = new int[1]; } @@ -111,12 +135,25 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL GLES20.glDeleteTextures(1, textureIdHolder, 0); } } finally { + if (display != null && !display.equals(EGL14.EGL_NO_DISPLAY)) { + EGL14.eglMakeCurrent( + display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + } if (surface != null && !surface.equals(EGL14.EGL_NO_SURFACE)) { EGL14.eglDestroySurface(display, surface); } if (context != null) { EGL14.eglDestroyContext(display, context); } + // EGL14.eglReleaseThread could crash before Android K (see [internal: b/11327779]). + if (Util.SDK_INT >= 19) { + EGL14.eglReleaseThread(); + } + if (display != null && !display.equals(EGL14.EGL_NO_DISPLAY)) { + // Android is unusual in that it uses a reference-counted EGLDisplay. So for + // every eglInitialize() we need an eglTerminate(). + EGL14.eglTerminate(display); + } display = null; context = null; surface = null; @@ -142,8 +179,20 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL @Override public void run() { + // Run on the provided handler thread when a new image frame is available. + dispatchOnFrameAvailable(); if (texture != null) { - texture.updateTexImage(); + try { + texture.updateTexImage(); + } catch (RuntimeException e) { + // Ignore + } + } + } + + private void dispatchOnFrameAvailable() { + if (callback != null) { + callback.onFrameAvailable(); } } @@ -220,9 +269,9 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL pbufferAttributes = new int[] { EGL14.EGL_WIDTH, - 1, + EGL_SURFACE_WIDTH, EGL14.EGL_HEIGHT, - 1, + EGL_SURFACE_HEIGHT, EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE, EGL14.EGL_NONE @@ -230,8 +279,10 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL } else { pbufferAttributes = new int[] { - EGL14.EGL_WIDTH, 1, - EGL14.EGL_HEIGHT, 1, + EGL14.EGL_WIDTH, + EGL_SURFACE_WIDTH, + EGL14.EGL_HEIGHT, + EGL_SURFACE_HEIGHT, EGL14.EGL_NONE }; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ErrorMessageProvider.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ErrorMessageProvider.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ErrorMessageProvider.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ErrorMessageProvider.java index 73960d7c2..e2fe095d0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ErrorMessageProvider.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ErrorMessageProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.util.Pair; diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventDispatcher.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventDispatcher.java new file mode 100755 index 000000000..26c02d8ae --- /dev/null +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventDispatcher.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.util; + +import android.os.Handler; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Event dispatcher which allows listener registration. + * + * @param The type of listener. + */ +public final class EventDispatcher { + + /** Functional interface to send an event. */ + public interface Event { + + /** + * Sends the event to a listener. + * + * @param listener The listener to send the event to. + */ + void sendTo(T listener); + } + + /** The list of listeners and handlers. */ + private final CopyOnWriteArrayList> listeners; + + /** Creates event dispatcher. */ + public EventDispatcher() { + listeners = new CopyOnWriteArrayList<>(); + } + + /** Adds listener to event dispatcher. */ + public void addListener(Handler handler, T eventListener) { + Assertions.checkArgument(handler != null && eventListener != null); + removeListener(eventListener); + listeners.add(new HandlerAndListener<>(handler, eventListener)); + } + + /** Removes listener from event dispatcher. */ + public void removeListener(T eventListener) { + for (HandlerAndListener handlerAndListener : listeners) { + if (handlerAndListener.listener == eventListener) { + listeners.remove(handlerAndListener); + } + } + } + + /** + * Dispatches an event to all registered listeners. + * + * @param event The {@link Event}. + */ + public void dispatch(Event event) { + for (HandlerAndListener handlerAndListener : listeners) { + T eventListener = handlerAndListener.listener; + handlerAndListener.handler.post(() -> event.sendTo(eventListener)); + } + } + + private static final class HandlerAndListener { + + public final Handler handler; + public final T listener; + + public HandlerAndListener(Handler handler, T eventListener) { + this.handler = handler; + this.listener = eventListener; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EventLogger.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventLogger.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EventLogger.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index ba07f71fc..3ca463e5e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/EventLogger.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -13,31 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import android.net.NetworkInfo; import android.os.SystemClock; import android.support.annotation.Nullable; import android.util.Log; import android.view.Surface; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.RendererCapabilities; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; -import org.telegram.messenger.exoplayer2.source.TrackGroup; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.MappingTrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.analytics.AnalyticsListener; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; +import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.MappingTrackSelector; +import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; @@ -364,13 +363,8 @@ public class EventLogger implements AnalyticsListener { } @Override - public void onViewportSizeChange(EventTime eventTime, int width, int height) { - logd(eventTime, "viewportSizeChanged", width + ", " + height); - } - - @Override - public void onNetworkTypeChanged(EventTime eventTime, @Nullable NetworkInfo networkInfo) { - logd(eventTime, "networkTypeChanged", networkInfo == null ? "none" : networkInfo.toString()); + public void onSurfaceSizeChanged(EventTime eventTime, int width, int height) { + logd(eventTime, "surfaceSizeChanged", width + ", " + height); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/FlacStreamInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/FlacStreamInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java index 65faa1ade..0df39e103 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/FlacStreamInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** * Holder for FLAC stream info. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/HandlerWrapper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/HandlerWrapper.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/HandlerWrapper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/HandlerWrapper.java index 562b3506b..8f1a6544c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/HandlerWrapper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/HandlerWrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.os.Handler; import android.os.Looper; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LibraryLoader.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LibraryLoader.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java index 64bf7e56d..c12bae0a0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LibraryLoader.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; /** * Configurable loader for native libraries. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LongArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LongArray.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LongArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LongArray.java index 9a565eff0..6d9725ad3 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/LongArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/LongArray.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import java.util.Arrays; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MediaClock.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MediaClock.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MediaClock.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MediaClock.java index 3adc0048d..a10298e45 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MediaClock.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MediaClock.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import org.telegram.messenger.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.PlaybackParameters; /** * Tracks the progression of media time. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MimeTypes.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MimeTypes.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index aa185d3c0..3392b8b8e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/MimeTypes.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.support.annotation.Nullable; import android.text.TextUtils; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; +import java.util.ArrayList; /** * Defines common MIME types and helper methods. @@ -92,7 +93,29 @@ public final class MimeTypes { public static final String APPLICATION_DVBSUBS = BASE_TYPE_APPLICATION + "/dvbsubs"; public static final String APPLICATION_EXIF = BASE_TYPE_APPLICATION + "/x-exif"; - private MimeTypes() {} + private static final ArrayList customMimeTypes = new ArrayList<>(); + + /** + * Registers a custom MIME type. Most applications do not need to call this method, as handling of + * standard MIME types is built in. These built-in MIME types take precedence over any registered + * via this method. If this method is used, it must be called before creating any player(s). + * + * @param mimeType The custom MIME type to register. + * @param codecPrefix The RFC 6381-style codec string prefix associated with the MIME type. + * @param trackType The {@link C}{@code .TRACK_TYPE_*} constant associated with the MIME type. + * This value is ignored if the top-level type of {@code mimeType} is audio, video or text. + */ + public static void registerCustomMimeType(String mimeType, String codecPrefix, int trackType) { + CustomMimeType customMimeType = new CustomMimeType(mimeType, codecPrefix, trackType); + int customMimeTypeCount = customMimeTypes.size(); + for (int i = 0; i < customMimeTypeCount; i++) { + if (mimeType.equals(customMimeTypes.get(i).mimeType)) { + customMimeTypes.remove(i); + break; + } + } + customMimeTypes.add(customMimeType); + } /** * Whether the top-level type of {@code mimeType} is audio. @@ -144,7 +167,7 @@ public final class MimeTypes { if (codecs == null) { return null; } - String[] codecList = codecs.split(","); + String[] codecList = Util.splitCodecs(codecs); for (String codec : codecList) { String mimeType = getMediaMimeType(codec); if (mimeType != null && isVideo(mimeType)) { @@ -164,7 +187,7 @@ public final class MimeTypes { if (codecs == null) { return null; } - String[] codecList = codecs.split(","); + String[] codecList = Util.splitCodecs(codecs); for (String codec : codecList) { String mimeType = getMediaMimeType(codec); if (mimeType != null && isAudio(mimeType)) { @@ -222,8 +245,9 @@ public final class MimeTypes { return MimeTypes.AUDIO_OPUS; } else if (codec.startsWith("vorbis")) { return MimeTypes.AUDIO_VORBIS; + } else { + return getCustomMimeTypeForCodec(codec); } - return null; } /** @@ -236,18 +260,28 @@ public final class MimeTypes { @Nullable public static String getMimeTypeFromMp4ObjectType(int objectType) { switch (objectType) { - case 0x60: - case 0x61: - return MimeTypes.VIDEO_MPEG2; case 0x20: return MimeTypes.VIDEO_MP4V; case 0x21: return MimeTypes.VIDEO_H264; case 0x23: return MimeTypes.VIDEO_H265; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + return MimeTypes.VIDEO_MPEG2; + case 0x6A: + return MimeTypes.VIDEO_MPEG; case 0x69: case 0x6B: return MimeTypes.AUDIO_MPEG; + case 0xA3: + return MimeTypes.VIDEO_VC1; + case 0xB1: + return MimeTypes.VIDEO_VP9; case 0x40: case 0x66: case 0x67: @@ -278,7 +312,7 @@ public final class MimeTypes { * @param mimeType The MIME type. * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type. */ - public static int getTrackType(String mimeType) { + public static int getTrackType(@Nullable String mimeType) { if (TextUtils.isEmpty(mimeType)) { return C.TRACK_TYPE_UNKNOWN; } else if (isAudio(mimeType)) { @@ -298,7 +332,7 @@ public final class MimeTypes { || APPLICATION_CAMERA_MOTION.equals(mimeType)) { return C.TRACK_TYPE_METADATA; } else { - return C.TRACK_TYPE_UNKNOWN; + return getTrackTypeForCustomMimeType(mimeType); } } @@ -355,4 +389,41 @@ public final class MimeTypes { return mimeType.substring(0, indexOfSlash); } + private static @Nullable String getCustomMimeTypeForCodec(String codec) { + int customMimeTypeCount = customMimeTypes.size(); + for (int i = 0; i < customMimeTypeCount; i++) { + CustomMimeType customMimeType = customMimeTypes.get(i); + if (codec.startsWith(customMimeType.codecPrefix)) { + return customMimeType.mimeType; + } + } + return null; + } + + private static int getTrackTypeForCustomMimeType(String mimeType) { + int customMimeTypeCount = customMimeTypes.size(); + for (int i = 0; i < customMimeTypeCount; i++) { + CustomMimeType customMimeType = customMimeTypes.get(i); + if (mimeType.equals(customMimeType.mimeType)) { + return customMimeType.trackType; + } + } + return C.TRACK_TYPE_UNKNOWN; + } + + private MimeTypes() { + // Prevent instantiation. + } + + private static final class CustomMimeType { + public final String mimeType; + public final String codecPrefix; + public final int trackType; + + public CustomMimeType(String mimeType, String codecPrefix, int trackType) { + this.mimeType = mimeType; + this.codecPrefix = codecPrefix; + this.trackType = trackType; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NalUnitUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NalUnitUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java index 9ae76592a..c4ed20546 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NalUnitUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.util.Log; import java.nio.ByteBuffer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NotificationUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NotificationUtil.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NotificationUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NotificationUtil.java index 26d87aa58..c93d7cd72 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/NotificationUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/NotificationUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.annotation.SuppressLint; import android.app.Notification; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableBitArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java similarity index 91% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableBitArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java index d8046a7c0..c60caf9ba 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableBitArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; /** * Wraps a byte array, providing methods that allow it to be read as a bitstream. @@ -175,7 +175,7 @@ public final class ParsableBitArray { bitOffset -= 8; returnValue |= (data[byteOffset++] & 0xFF) << bitOffset; } - returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset; + returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset); returnValue &= 0xFFFFFFFF >>> (32 - numBits); if (bitOffset == 8) { bitOffset = 0; @@ -199,17 +199,18 @@ public final class ParsableBitArray { int to = offset + (numBits >> 3) /* numBits / 8 */; for (int i = offset; i < to; i++) { buffer[i] = (byte) (data[byteOffset++] << bitOffset); - buffer[i] |= (data[byteOffset] & 0xFF) >> (8 - bitOffset); + buffer[i] = (byte) (buffer[i] | ((data[byteOffset] & 0xFF) >> (8 - bitOffset))); } // Trailing bits. int bitsLeft = numBits & 7 /* numBits % 8 */; if (bitsLeft == 0) { return; } - buffer[to] &= 0xFF >> bitsLeft; // Set to 0 the bits that are going to be overwritten. + // Set bits that are going to be overwritten to 0. + buffer[to] = (byte) (buffer[to] & (0xFF >> bitsLeft)); if (bitOffset + bitsLeft > 8) { // We read the rest of data[byteOffset] and increase byteOffset. - buffer[to] |= (byte) ((data[byteOffset++] & 0xFF) << bitOffset); + buffer[to] = (byte) (buffer[to] | ((data[byteOffset++] & 0xFF) << bitOffset)); bitOffset -= 8; } bitOffset += bitsLeft; @@ -280,9 +281,10 @@ public final class ParsableBitArray { int firstByteReadSize = Math.min(8 - bitOffset, numBits); int firstByteRightPaddingSize = 8 - bitOffset - firstByteReadSize; int firstByteBitmask = (0xFF00 >> bitOffset) | ((1 << firstByteRightPaddingSize) - 1); - data[byteOffset] &= firstByteBitmask; + data[byteOffset] = (byte) (data[byteOffset] & firstByteBitmask); int firstByteInputBits = value >>> (numBits - firstByteReadSize); - data[byteOffset] |= firstByteInputBits << firstByteRightPaddingSize; + data[byteOffset] = + (byte) (data[byteOffset] | (firstByteInputBits << firstByteRightPaddingSize)); remainingBitsToRead -= firstByteReadSize; int currentByteIndex = byteOffset + 1; while (remainingBitsToRead > 8) { @@ -290,9 +292,11 @@ public final class ParsableBitArray { remainingBitsToRead -= 8; } int lastByteRightPaddingSize = 8 - remainingBitsToRead; - data[currentByteIndex] &= (1 << lastByteRightPaddingSize) - 1; + data[currentByteIndex] = + (byte) (data[currentByteIndex] & ((1 << lastByteRightPaddingSize) - 1)); int lastByteInput = value & ((1 << remainingBitsToRead) - 1); - data[currentByteIndex] |= lastByteInput << lastByteRightPaddingSize; + data[currentByteIndex] = + (byte) (data[currentByteIndex] | (lastByteInput << lastByteRightPaddingSize)); skipBits(numBits); assertValidOffset(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableByteArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableByteArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java index 7c0abe121..5190896d9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableByteArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; import java.nio.ByteBuffer; import java.nio.charset.Charset; @@ -470,7 +470,7 @@ public final class ParsableByteArray { if (lastIndex < limit && data[lastIndex] == 0) { stringLength--; } - String result = new String(data, position, stringLength); + String result = Util.fromUtf8Bytes(data, position, stringLength); position += length; return result; } @@ -489,7 +489,7 @@ public final class ParsableByteArray { while (stringLimit < limit && data[stringLimit] != 0) { stringLimit++; } - String string = new String(data, position, stringLimit - position); + String string = Util.fromUtf8Bytes(data, position, stringLimit - position); position = stringLimit; if (position < limit) { position++; @@ -520,7 +520,7 @@ public final class ParsableByteArray { // There's a byte order mark at the start of the line. Discard it. position += 3; } - String line = new String(data, position, lineLimit - position); + String line = Util.fromUtf8Bytes(data, position, lineLimit - position); position = lineLimit; if (position == limit) { return line; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableNalUnitBitArray.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableNalUnitBitArray.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java index f232b8bf8..3a7202c67 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ParsableNalUnitBitArray.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; /** * Wraps a byte array, providing methods that allow it to be read as a NAL unit bitstream. @@ -140,7 +140,7 @@ public final class ParsableNalUnitBitArray { returnValue |= (data[byteOffset] & 0xFF) << bitOffset; byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; } - returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset; + returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset); returnValue &= 0xFFFFFFFF >>> (32 - numBits); if (bitOffset == 8) { bitOffset = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Predicate.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Predicate.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Predicate.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Predicate.java index 2f30910a8..b582cf3f7 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Predicate.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Predicate.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; /** - * Determines a true of false value for a given input. + * Determines a true or false value for a given input. * * @param The input type of the predicate. */ diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/PriorityTaskManager.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/PriorityTaskManager.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/PriorityTaskManager.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/PriorityTaskManager.java index c8cffacd8..2516b538c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/PriorityTaskManager.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/PriorityTaskManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import java.io.IOException; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/RepeatModeUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/RepeatModeUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java index bb00420fd..53cb05123 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/RepeatModeUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.support.annotation.IntDef; -import org.telegram.messenger.exoplayer2.Player; +import com.google.android.exoplayer2.Player; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ReusableBufferedOutputStream.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ReusableBufferedOutputStream.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ReusableBufferedOutputStream.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ReusableBufferedOutputStream.java index 21880857f..1db3d2c1f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/ReusableBufferedOutputStream.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/ReusableBufferedOutputStream.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import java.io.BufferedOutputStream; import java.io.IOException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SlidingPercentile.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SlidingPercentile.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SlidingPercentile.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SlidingPercentile.java index 27cf56521..c43b1929c 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SlidingPercentile.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SlidingPercentile.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import java.util.ArrayList; import java.util.Collections; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/StandaloneMediaClock.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/StandaloneMediaClock.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java index f6679998c..b1f53416f 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/StandaloneMediaClock.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.PlaybackParameters; /** * A {@link MediaClock} whose position advances with real time based on the playback parameters when diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemClock.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemClock.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemClock.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemClock.java index 965ddebc4..72d3df46e 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemClock.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemClock.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.os.Handler; import android.os.Handler.Callback; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemHandlerWrapper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemHandlerWrapper.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemHandlerWrapper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemHandlerWrapper.java index d6a32e826..ee469a5b2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/SystemHandlerWrapper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/SystemHandlerWrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.os.Looper; import android.os.Message; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TimestampAdjuster.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TimestampAdjuster.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java index 2e68b682a..08e2bd066 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TimestampAdjuster.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; -import org.telegram.messenger.exoplayer2.C; +import com.google.android.exoplayer2.C; /** * Offsets timestamps according to an initial sample timestamp offset. MPEG-2 TS timestamps scaling diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TraceUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TraceUtil.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TraceUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TraceUtil.java index 7f77a4a64..8fb409c04 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/TraceUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/TraceUtil.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.annotation.TargetApi; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; /** * Calls through to {@link android.os.Trace} methods on supported API levels. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/UriUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/UriUtil.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/UriUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/UriUtil.java index bc4173dd8..071ebf208 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/UriUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/UriUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.net.Uri; import android.text.TextUtils; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Util.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java similarity index 83% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Util.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java index 6c8a39f40..209964569 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/Util.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import android.Manifest.permission; import android.annotation.TargetApi; @@ -25,21 +25,26 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Point; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.os.Parcel; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.Display; import android.view.WindowManager; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayerLibraryInfo; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.SeekParameters; -import org.telegram.messenger.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.upstream.DataSource; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; @@ -63,6 +68,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.EnsuresNonNull; +import org.checkerframework.checker.nullness.qual.PolyNull; /** * Miscellaneous utility methods. @@ -225,6 +233,17 @@ public final class Util { list.subList(fromIndex, toIndex).clear(); } + /** + * Casts a nullable variable to a non-null variable without runtime null check. + * + *

    Use {@link Assertions#checkNotNull(Object)} to throw if the value is null. + */ + @SuppressWarnings({"contracts.postcondition.not.satisfied", "return.type.incompatible"}) + @EnsuresNonNull("#1") + public static T castNonNull(@Nullable T value) { + return value; + } + /** * Copies and optionally truncates an array. Prevents null array elements created by {@link * Arrays#copyOf(Object[], int)} by ensuring the new length does not exceed the current length. @@ -233,12 +252,53 @@ public final class Util { * @param length The output array length. Must be less or equal to the length of the input array. * @return The copied array. */ - @SuppressWarnings("nullness:assignment.type.incompatible") + @SuppressWarnings({"nullness:argument.type.incompatible", "nullness:return.type.incompatible"}) public static T[] nullSafeArrayCopy(T[] input, int length) { Assertions.checkArgument(length <= input.length); return Arrays.copyOf(input, length); } + /** + * Creates a {@link Handler} with the specified {@link Handler.Callback} on the current {@link + * Looper} thread. The method accepts partially initialized objects as callback under the + * assumption that the Handler won't be used to send messages until the callback is fully + * initialized. + * + *

    If the current thread doesn't have a {@link Looper}, the application's main thread {@link + * Looper} is used. + * + * @param callback A {@link Handler.Callback}. May be a partially initialized class. + * @return A {@link Handler} with the specified callback on the current {@link Looper} thread. + */ + public static Handler createHandler(Handler.@UnknownInitialization Callback callback) { + return createHandler(getLooper(), callback); + } + + /** + * Creates a {@link Handler} with the specified {@link Handler.Callback} on the specified {@link + * Looper} thread. The method accepts partially initialized objects as callback under the + * assumption that the Handler won't be used to send messages until the callback is fully + * initialized. + * + * @param looper A {@link Looper} to run the callback on. + * @param callback A {@link Handler.Callback}. May be a partially initialized class. + * @return A {@link Handler} with the specified callback on the current {@link Looper} thread. + */ + @SuppressWarnings({"nullness:argument.type.incompatible", "nullness:return.type.incompatible"}) + public static Handler createHandler( + Looper looper, Handler.@UnknownInitialization Callback callback) { + return new Handler(looper, callback); + } + + /** + * Returns the {@link Looper} associated with the current thread, or the {@link Looper} of the + * application's main thread if the current thread doesn't have a {@link Looper}. + */ + public static Looper getLooper() { + Looper myLooper = Looper.myLooper(); + return myLooper != null ? myLooper : Looper.getMainLooper(); + } + /** * Instantiates a new single threaded executor whose thread has the specified name. * @@ -311,10 +371,10 @@ public final class Util { * Returns a normalized RFC 639-2/T code for {@code language}. * * @param language A case-insensitive ISO 639 alpha-2 or alpha-3 language code. - * @return The all-lowercase normalized code, or null if the input was null, or - * {@code language.toLowerCase()} if the language could not be normalized. + * @return The all-lowercase normalized code, or null if the input was null, or {@code + * language.toLowerCase()} if the language could not be normalized. */ - public static String normalizeLanguageCode(String language) { + public static @Nullable String normalizeLanguageCode(@Nullable String language) { try { return language == null ? null : new Locale(language).getISO3Language(); } catch (MissingResourceException e) { @@ -332,6 +392,18 @@ public final class Util { return new String(bytes, Charset.forName(C.UTF8_NAME)); } + /** + * Returns a new {@link String} constructed by decoding UTF-8 encoded bytes in a subarray. + * + * @param bytes The UTF-8 encoded bytes to decode. + * @param offset The index of the first byte to decode. + * @param length The number of bytes to decode. + * @return The string. + */ + public static String fromUtf8Bytes(byte[] bytes, int offset, int length) { + return new String(bytes, offset, length, Charset.forName(C.UTF8_NAME)); + } + /** * Returns a new byte array containing the code points of a {@link String} encoded using UTF-8. * @@ -342,6 +414,33 @@ public final class Util { return value.getBytes(Charset.forName(C.UTF8_NAME)); } + /** + * Splits a string using {@code value.split(regex, -1}). Note: this is is similar to {@link + * String#split(String)} but empty matches at the end of the string will not be omitted from the + * returned array. + * + * @param value The string to split. + * @param regex A delimiting regular expression. + * @return The array of strings resulting from splitting the string. + */ + public static String[] split(String value, String regex) { + return value.split(regex, /* limit= */ -1); + } + + /** + * Splits the string at the first occurrence of the delimiter {@code regex}. If the delimiter does + * not match, returns an array with one element which is the input string. If the delimiter does + * match, returns an array with the portion of the string before the delimiter and the rest of the + * string. + * + * @param value The string. + * @param regex A delimiting regular expression. + * @return The string split by the first occurrence of the delimiter. + */ + public static String[] splitAtFirst(String value, String regex) { + return value.split(regex, /* limit= */ 2); + } + /** * Returns whether the given character is a carriage return ('\r') or a line feed ('\n'). * @@ -358,8 +457,8 @@ public final class Util { * @param text The text to convert. * @return The lower case text, or null if {@code text} is null. */ - public static String toLowerInvariant(String text) { - return text == null ? null : text.toLowerCase(Locale.US); + public static @PolyNull String toLowerInvariant(@PolyNull String text) { + return text == null ? text : text.toLowerCase(Locale.US); } /** @@ -368,8 +467,8 @@ public final class Util { * @param text The text to convert. * @return The upper case text, or null if {@code text} is null. */ - public static String toUpperInvariant(String text) { - return text == null ? null : text.toUpperCase(Locale.US); + public static @PolyNull String toUpperInvariant(@PolyNull String text) { + return text == null ? text : text.toUpperCase(Locale.US); } /** @@ -540,10 +639,10 @@ public final class Util { /** * Returns the index of the largest element in {@code list} that is less than (or optionally equal * to) a specified {@code value}. - *

    - * The search is performed using a binary search algorithm, so the list must be sorted. If the - * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the - * index of the first one will be returned. + * + *

    The search is performed using a binary search algorithm, so the list must be sorted. If the + * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the index + * of the first one will be returned. * * @param The type of values being searched. * @param list The list to search. @@ -556,8 +655,11 @@ public final class Util { * @return The index of the largest element in {@code list} that is less than (or optionally equal * to) {@code value}. */ - public static int binarySearchFloor(List> list, T value, - boolean inclusive, boolean stayInBounds) { + public static > int binarySearchFloor( + List> list, + T value, + boolean inclusive, + boolean stayInBounds) { int index = Collections.binarySearch(list, value); if (index < 0) { index = -(index + 2); @@ -606,10 +708,10 @@ public final class Util { /** * Returns the index of the smallest element in {@code list} that is greater than (or optionally * equal to) a specified value. - *

    - * The search is performed using a binary search algorithm, so the list must be sorted. If the - * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the - * index of the last one will be returned. + * + *

    The search is performed using a binary search algorithm, so the list must be sorted. If the + * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the index + * of the last one will be returned. * * @param The type of values being searched. * @param list The list to search. @@ -618,13 +720,16 @@ public final class Util { * index. If false then the returned index corresponds to the smallest element strictly * greater than the value. * @param stayInBounds If true, then {@code (list.size() - 1)} will be returned in the case that - * the value is greater than the largest element in the list. If false then - * {@code list.size()} will be returned. + * the value is greater than the largest element in the list. If false then {@code + * list.size()} will be returned. * @return The index of the smallest element in {@code list} that is greater than (or optionally * equal to) {@code value}. */ - public static int binarySearchCeil(List> list, T value, - boolean inclusive, boolean stayInBounds) { + public static > int binarySearchCeil( + List> list, + T value, + boolean inclusive, + boolean stayInBounds) { int index = Collections.binarySearch(list, value); if (index < 0) { index = ~index; @@ -883,7 +988,7 @@ public final class Util { * @param list A list of integers. * @return The list in array form, or null if the input list was null. */ - public static int[] toArray(List list) { + public static int @PolyNull [] toArray(@PolyNull List list) { if (list == null) { return null; } @@ -966,19 +1071,19 @@ public final class Util { } /** - * Returns a copy of {@code codecs} without the codecs whose track type doesn't match - * {@code trackType}. + * Returns a copy of {@code codecs} without the codecs whose track type doesn't match {@code + * trackType}. * * @param codecs A codec sequence string, as defined in RFC 6381. * @param trackType One of {@link C}{@code .TRACK_TYPE_*}. - * @return A copy of {@code codecs} without the codecs whose track type doesn't match - * {@code trackType}. + * @return A copy of {@code codecs} without the codecs whose track type doesn't match {@code + * trackType}. */ - public static String getCodecsOfType(String codecs, int trackType) { - if (TextUtils.isEmpty(codecs)) { + public static @Nullable String getCodecsOfType(String codecs, int trackType) { + String[] codecArray = splitCodecs(codecs); + if (codecArray.length == 0) { return null; } - String[] codecArray = codecs.trim().split("(\\s*,\\s*)"); StringBuilder builder = new StringBuilder(); for (String codec : codecArray) { if (trackType == MimeTypes.getTrackTypeOfCodec(codec)) { @@ -991,6 +1096,19 @@ public final class Util { return builder.length() > 0 ? builder.toString() : null; } + /** + * Splits a codecs sequence string, as defined in RFC 6381, into individual codec strings. + * + * @param codecs A codec sequence string, as defined in RFC 6381. + * @return The split codecs, or an array of length zero if the input was empty. + */ + public static String[] splitCodecs(String codecs) { + if (TextUtils.isEmpty(codecs)) { + return new String[0]; + } + return split(codecs.trim(), "(\\s*,\\s*)"); + } + /** * Converts a sample bit depth to a corresponding PCM encoding constant. * @@ -1017,12 +1135,12 @@ public final class Util { } /** - * Returns whether {@code encoding} is one of the PCM encodings. + * Returns whether {@code encoding} is one of the linear PCM encodings. * * @param encoding The encoding of the audio data. * @return Whether the encoding is one of the PCM encodings. */ - public static boolean isEncodingPcm(@C.Encoding int encoding) { + public static boolean isEncodingLinearPcm(@C.Encoding int encoding) { return encoding == C.ENCODING_PCM_8BIT || encoding == C.ENCODING_PCM_16BIT || encoding == C.ENCODING_PCM_24BIT @@ -1151,7 +1269,7 @@ public final class Util { * "clearkey"}. * @return The derived {@link UUID}, or {@code null} if one could not be derived. */ - public static UUID getDrmUuid(String drmScheme) { + public static @Nullable UUID getDrmUuid(String drmScheme) { switch (Util.toLowerInvariant(drmScheme)) { case "widevine": return C.WIDEVINE_UUID; @@ -1327,7 +1445,7 @@ public final class Util { * @return The original value of the file name before it was escaped, or null if the escaped * fileName seems invalid. */ - public static String unescapeFileName(String fileName) { + public static @Nullable String unescapeFileName(String fileName) { int length = fileName.length(); int percentCharacterCount = 0; for (int i = 0; i < length; i++) { @@ -1373,8 +1491,9 @@ public final class Util { /** Recursively deletes a directory and its content. */ public static void recursiveDelete(File fileOrDirectory) { - if (fileOrDirectory.isDirectory()) { - for (File child : fileOrDirectory.listFiles()) { + File[] directoryFiles = fileOrDirectory.listFiles(); + if (directoryFiles != null) { + for (File child : directoryFiles) { recursiveDelete(child); } } @@ -1412,6 +1531,72 @@ public final class Util { return initialValue; } + /** + * Returns the {@link C.NetworkType} of the current network connection. {@link + * C#NETWORK_TYPE_UNKNOWN} will be returned if the {@code ACCESS_NETWORK_STATE} permission is not + * granted or the network connection type couldn't be determined. + * + * @param context A context to access the connectivity manager. + * @return The {@link C.NetworkType} of the current network connection, or {@link + * C#NETWORK_TYPE_UNKNOWN} if the {@code ACCESS_NETWORK_STATE} permission is not granted or + * {@code context} is null. + */ + public static @C.NetworkType int getNetworkType(@Nullable Context context) { + if (context == null) { + return C.NETWORK_TYPE_UNKNOWN; + } + NetworkInfo networkInfo; + try { + ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager == null) { + return C.NETWORK_TYPE_UNKNOWN; + } + networkInfo = connectivityManager.getActiveNetworkInfo(); + } catch (SecurityException e) { + // Permission ACCESS_NETWORK_STATE not granted. + return C.NETWORK_TYPE_UNKNOWN; + } + if (networkInfo == null || !networkInfo.isConnected()) { + return C.NETWORK_TYPE_OFFLINE; + } + switch (networkInfo.getType()) { + case ConnectivityManager.TYPE_WIFI: + return C.NETWORK_TYPE_WIFI; + case ConnectivityManager.TYPE_WIMAX: + return C.NETWORK_TYPE_4G; + case ConnectivityManager.TYPE_MOBILE: + case ConnectivityManager.TYPE_MOBILE_DUN: + case ConnectivityManager.TYPE_MOBILE_HIPRI: + return getMobileNetworkType(networkInfo); + case ConnectivityManager.TYPE_ETHERNET: + return C.NETWORK_TYPE_ETHERNET; + default: // Ethernet, VPN, Bluetooth, Dummy. + return C.NETWORK_TYPE_OTHER; + } + } + + /** + * Returns the upper-case ISO 3166-1 alpha-2 country code of the current registered operator's MCC + * (Mobile Country Code), or the country code of the default Locale if not available. + * + * @param context A context to access the telephony service. If null, only the Locale can be used. + * @return The upper-case ISO 3166-1 alpha-2 country code, or an empty String if unavailable. + */ + public static String getCountryCode(@Nullable Context context) { + if (context != null) { + TelephonyManager telephonyManager = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null) { + String countryCode = telephonyManager.getNetworkCountryIso(); + if (!TextUtils.isEmpty(countryCode)) { + return toUpperInvariant(countryCode); + } + } + } + return toUpperInvariant(Locale.getDefault().getCountry()); + } + /** * Gets the physical size of the default display, in pixels. * @@ -1454,7 +1639,7 @@ public final class Util { // If we managed to read sys.display-size, attempt to parse it. if (!TextUtils.isEmpty(sysDisplaySize)) { try { - String[] sysDisplaySizeParts = sysDisplaySize.trim().split("x"); + String[] sysDisplaySizeParts = split(sysDisplaySize.trim(), "x"); if (sysDisplaySizeParts.length == 2) { int width = Integer.parseInt(sysDisplaySizeParts[0]); int height = Integer.parseInt(sysDisplaySizeParts[1]); @@ -1506,6 +1691,36 @@ public final class Util { outSize.y = display.getHeight(); } + private static @C.NetworkType int getMobileNetworkType(NetworkInfo networkInfo) { + switch (networkInfo.getSubtype()) { + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_GPRS: + return C.NETWORK_TYPE_2G; + case TelephonyManager.NETWORK_TYPE_1xRTT: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_IDEN: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return C.NETWORK_TYPE_3G; + case TelephonyManager.NETWORK_TYPE_LTE: + return C.NETWORK_TYPE_4G; + case TelephonyManager.NETWORK_TYPE_IWLAN: + return C.NETWORK_TYPE_WIFI; + case TelephonyManager.NETWORK_TYPE_GSM: + case TelephonyManager.NETWORK_TYPE_UNKNOWN: + default: // Future mobile network types. + return C.NETWORK_TYPE_CELLULAR_UNKNOWN; + } + } + /** * Allows the CRC calculation to be done byte by byte instead of bit per bit being the order * "most significant bit first". diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/XmlPullParserUtil.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/XmlPullParserUtil.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/XmlPullParserUtil.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/util/XmlPullParserUtil.java index db279c878..84a6e4ceb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/util/XmlPullParserUtil.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/XmlPullParserUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.util; +package com.google.android.exoplayer2.util; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/AvcConfig.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/AvcConfig.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java index 0624ca1fb..3886fdfb2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/AvcConfig.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.util.CodecSpecificDataUtil; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil.SpsData; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.NalUnitUtil.SpsData; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.ArrayList; import java.util.List; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/ColorInfo.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/ColorInfo.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/ColorInfo.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/ColorInfo.java index bcdafa495..77ca936a9 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/ColorInfo.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/ColorInfo.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.util.Util; import java.util.Arrays; /** @@ -50,10 +50,8 @@ public final class ColorInfo implements Parcelable { @C.ColorTransfer public final int colorTransfer; - /** - * HdrStaticInfo as defined in CTA-861.3. - */ - public final byte[] hdrStaticInfo; + /** HdrStaticInfo as defined in CTA-861.3, or null if none specified. */ + public final @Nullable byte[] hdrStaticInfo; // Lazily initialized hashcode. private int hashCode; @@ -64,10 +62,13 @@ public final class ColorInfo implements Parcelable { * @param colorSpace The color space of the video. * @param colorRange The color range of the video. * @param colorTransfer The color transfer characteristics of the video. - * @param hdrStaticInfo HdrStaticInfo as defined in CTA-861.3. + * @param hdrStaticInfo HdrStaticInfo as defined in CTA-861.3, or null if none specified. */ - public ColorInfo(@C.ColorSpace int colorSpace, @C.ColorRange int colorRange, - @C.ColorTransfer int colorTransfer, byte[] hdrStaticInfo) { + public ColorInfo( + @C.ColorSpace int colorSpace, + @C.ColorRange int colorRange, + @C.ColorTransfer int colorTransfer, + @Nullable byte[] hdrStaticInfo) { this.colorSpace = colorSpace; this.colorRange = colorRange; this.colorTransfer = colorTransfer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/DummySurface.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/DummySurface.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/DummySurface.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index ce77871d5..996e6f30a 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/DummySurface.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; -import static org.telegram.messenger.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_NONE; -import static org.telegram.messenger.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_PROTECTED_PBUFFER; -import static org.telegram.messenger.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_SURFACELESS_CONTEXT; +import static com.google.android.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_NONE; +import static com.google.android.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_PROTECTED_PBUFFER; +import static com.google.android.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_SURFACELESS_CONTEXT; import android.annotation.TargetApi; import android.content.Context; @@ -32,11 +32,12 @@ import android.os.Message; import android.support.annotation.Nullable; import android.util.Log; import android.view.Surface; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.EGLSurfaceTexture; -import org.telegram.messenger.exoplayer2.util.EGLSurfaceTexture.SecureMode; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.EGLSurfaceTexture; +import com.google.android.exoplayer2.util.EGLSurfaceTexture.SecureMode; +import com.google.android.exoplayer2.util.Util; import javax.microedition.khronos.egl.EGL10; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * A dummy {@link Surface}. @@ -155,8 +156,8 @@ public final class DummySurface extends Surface { private static final int MSG_INIT = 1; private static final int MSG_RELEASE = 2; - private EGLSurfaceTexture eglSurfaceTexure; - private Handler handler; + private @MonotonicNonNull EGLSurfaceTexture eglSurfaceTexture; + private @MonotonicNonNull Handler handler; private @Nullable Error initError; private @Nullable RuntimeException initException; private @Nullable DummySurface surface; @@ -168,7 +169,7 @@ public final class DummySurface extends Surface { public DummySurface init(@SecureMode int secureMode) { start(); handler = new Handler(getLooper(), /* callback= */ this); - eglSurfaceTexure = new EGLSurfaceTexture(handler); + eglSurfaceTexture = new EGLSurfaceTexture(handler); boolean wasInterrupted = false; synchronized (this) { handler.obtainMessage(MSG_INIT, secureMode, 0).sendToTarget(); @@ -231,16 +232,16 @@ public final class DummySurface extends Surface { } private void initInternal(@SecureMode int secureMode) { - Assertions.checkNotNull(eglSurfaceTexure); - eglSurfaceTexure.init(secureMode); + Assertions.checkNotNull(eglSurfaceTexture); + eglSurfaceTexture.init(secureMode); this.surface = new DummySurface( - this, eglSurfaceTexure.getSurfaceTexture(), secureMode != SECURE_MODE_NONE); + this, eglSurfaceTexture.getSurfaceTexture(), secureMode != SECURE_MODE_NONE); } private void releaseInternal() { - Assertions.checkNotNull(eglSurfaceTexure); - eglSurfaceTexure.release(); + Assertions.checkNotNull(eglSurfaceTexture); + eglSurfaceTexture.release(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/HevcConfig.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java similarity index 88% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/HevcConfig.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java index 84db3b167..089ff6343 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/HevcConfig.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; -import org.telegram.messenger.exoplayer2.ParserException; -import org.telegram.messenger.exoplayer2.util.NalUnitUtil; -import org.telegram.messenger.exoplayer2.util.ParsableByteArray; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.NalUnitUtil; +import com.google.android.exoplayer2.util.ParsableByteArray; import java.util.Collections; import java.util.List; @@ -26,7 +27,7 @@ import java.util.List; */ public final class HevcConfig { - public final List initializationData; + public final @Nullable List initializationData; public final int nalUnitLengthFieldLength; /** @@ -82,7 +83,7 @@ public final class HevcConfig { } } - private HevcConfig(List initializationData, int nalUnitLengthFieldLength) { + private HevcConfig(@Nullable List initializationData, int nalUnitLengthFieldLength) { this.initializationData = initializationData; this.nalUnitLengthFieldLength = nalUnitLengthFieldLength; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/MediaCodecVideoRenderer.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java similarity index 82% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/MediaCodecVideoRenderer.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 76ed44e00..b5ef091bf 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -30,27 +30,28 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import android.view.Surface; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlayerMessage.Target; -import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; -import org.telegram.messenger.exoplayer2.drm.DrmInitData; -import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; -import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecInfo; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecRenderer; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; -import org.telegram.messenger.exoplayer2.mediacodec.MediaFormatUtil; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.MimeTypes; -import org.telegram.messenger.exoplayer2.util.TraceUtil; -import org.telegram.messenger.exoplayer2.util.Util; -import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener.EventDispatcher; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlayerMessage.Target; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; +import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; +import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer; +import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; +import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; +import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import com.google.android.exoplayer2.mediacodec.MediaFormatUtil; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.TraceUtil; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher; import java.nio.ByteBuffer; +import java.util.List; /** * Decodes and renders video using {@link MediaCodec}. @@ -84,6 +85,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { // pending output streams that have fewer frames than the codec latency. private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10; + private static boolean evaluatedDeviceNeedsSetOutputSurfaceWorkaround; + private static boolean deviceNeedsSetOutputSurfaceWorkaround; + private final Context context; private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper; private final EventDispatcher eventDispatcher; @@ -201,11 +205,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { @Nullable DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, @Nullable Handler eventHandler, @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { - super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys); + super( + C.TRACK_TYPE_VIDEO, + mediaCodecSelector, + drmSessionManager, + playClearSamplesWithoutKeys, + /* assumedMinimumCodecOperatingRate= */ 30); this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.context = context.getApplicationContext(); - frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); + frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(this.context); eventDispatcher = new EventDispatcher(eventHandler, eventListener); deviceNeedsAutoFrcWorkaround = deviceNeedsAutoFrcWorkaround(); pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; @@ -236,15 +245,21 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption; } } - MediaCodecInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, - requiresSecureDecryption); - if (decoderInfo == null) { - return requiresSecureDecryption && mediaCodecSelector.getDecoderInfo(mimeType, false) != null - ? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE; + List decoderInfos = + mediaCodecSelector.getDecoderInfos(format, requiresSecureDecryption); + if (decoderInfos.isEmpty()) { + return requiresSecureDecryption + && !mediaCodecSelector + .getDecoderInfos(format, /* requiresSecureDecoder= */ false) + .isEmpty() + ? FORMAT_UNSUPPORTED_DRM + : FORMAT_UNSUPPORTED_SUBTYPE; } if (!supportsFormatDrm(drmSessionManager, drmInitData)) { return FORMAT_UNSUPPORTED_DRM; } + // Check capabilities for the first decoder in the list, which takes priority. + MediaCodecInfo decoderInfo = decoderInfos.get(0); boolean decoderCapable = decoderInfo.isCodecSupported(format.codecs); if (decoderCapable && format.width > 0 && format.height > 0) { if (Util.SDK_INT >= 21) { @@ -435,11 +450,21 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } @Override - protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, - MediaCrypto crypto) throws DecoderQueryException { + protected void configureCodec( + MediaCodecInfo codecInfo, + MediaCodec codec, + Format format, + MediaCrypto crypto, + float codecOperatingRate) + throws DecoderQueryException { codecMaxValues = getCodecMaxValues(codecInfo, format, getStreamFormats()); - MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround, - tunnelingAudioSessionId); + MediaFormat mediaFormat = + getMediaFormat( + format, + codecMaxValues, + codecOperatingRate, + deviceNeedsAutoFrcWorkaround, + tunnelingAudioSessionId); if (surface == null) { Assertions.checkState(shouldUseDummySurface(codecInfo)); if (dummySurface == null) { @@ -459,7 +484,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { if (areAdaptationCompatible(codecInfo.adaptive, oldFormat, newFormat) && newFormat.width <= codecMaxValues.width && newFormat.height <= codecMaxValues.height - && getMaxInputSize(newFormat) <= codecMaxValues.inputSize) { + && getMaxInputSize(codecInfo, newFormat) <= codecMaxValues.inputSize) { return oldFormat.initializationDataEquals(newFormat) ? KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION : KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION; @@ -491,6 +516,21 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { buffersInCodecCount = 0; } + @Override + protected float getCodecOperatingRate( + float operatingRate, Format format, Format[] streamFormats) { + // Use the highest known stream frame-rate up front, to avoid having to reconfigure the codec + // should an adaptive switch to that stream occur. + float maxFrameRate = -1; + for (Format streamFormat : streamFormats) { + float streamFrameRate = streamFormat.frameRate; + if (streamFrameRate != Format.NO_VALUE) { + maxFrameRate = Math.max(maxFrameRate, streamFrameRate); + } + } + return maxFrameRate == -1 ? CODEC_OPERATING_RATE_UNSET : (maxFrameRate * operatingRate); + } + @Override protected void onCodecInitialized(String name, long initializedTimestampMs, long initializationDurationMs) { @@ -926,6 +966,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { * * @param format The format of media. * @param codecMaxValues Codec max values that should be used when configuring the decoder. + * @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if + * no codec operating rate should be set. * @param deviceNeedsAutoFrcWorkaround Whether the device is known to enable frame-rate conversion * logic that negatively impacts ExoPlayer. * @param tunnelingAudioSessionId The audio session id to use for tunneling, or {@link @@ -936,6 +978,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { protected MediaFormat getMediaFormat( Format format, CodecMaxValues codecMaxValues, + float codecOperatingRate, boolean deviceNeedsAutoFrcWorkaround, int tunnelingAudioSessionId) { MediaFormat mediaFormat = new MediaFormat(); @@ -956,6 +999,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { // Set codec configuration values. if (Util.SDK_INT >= 23) { mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */); + if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) { + mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate); + } } if (deviceNeedsAutoFrcWorkaround) { mediaFormat.setInteger("auto-frc", 0); @@ -981,7 +1027,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { throws DecoderQueryException { int maxWidth = format.width; int maxHeight = format.height; - int maxInputSize = getMaxInputSize(format); + int maxInputSize = getMaxInputSize(codecInfo, format); if (streamFormats.length == 1) { // The single entry in streamFormats must correspond to the format for which the codec is // being configured. @@ -994,7 +1040,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { (streamFormat.width == Format.NO_VALUE || streamFormat.height == Format.NO_VALUE); maxWidth = Math.max(maxWidth, streamFormat.width); maxHeight = Math.max(maxHeight, streamFormat.height); - maxInputSize = Math.max(maxInputSize, getMaxInputSize(streamFormat)); + maxInputSize = Math.max(maxInputSize, getMaxInputSize(codecInfo, streamFormat)); } } if (haveUnknownDimensions) { @@ -1004,7 +1050,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maxWidth = Math.max(maxWidth, codecMaxSize.x); maxHeight = Math.max(maxHeight, codecMaxSize.y); maxInputSize = - Math.max(maxInputSize, getMaxInputSize(format.sampleMimeType, maxWidth, maxHeight)); + Math.max( + maxInputSize, + getMaxInputSize(codecInfo, format.sampleMimeType, maxWidth, maxHeight)); Log.w(TAG, "Codec max resolution adjusted to: " + maxWidth + "x" + maxHeight); } } @@ -1053,13 +1101,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } /** - * Returns a maximum input buffer size for a given format. + * Returns a maximum input buffer size for a given codec and format. * + * @param codecInfo Information about the {@link MediaCodec} being configured. * @param format The format. * @return A maximum input buffer size in bytes, or {@link Format#NO_VALUE} if a maximum could not * be determined. */ - private static int getMaxInputSize(Format format) { + private static int getMaxInputSize(MediaCodecInfo codecInfo, Format format) { if (format.maxInputSize != Format.NO_VALUE) { // The format defines an explicit maximum input size. Add the total size of initialization // data buffers, as they may need to be queued in the same input buffer as the largest sample. @@ -1072,20 +1121,22 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } else { // Calculated maximum input sizes are overestimates, so it's not necessary to add the size of // initialization data. - return getMaxInputSize(format.sampleMimeType, format.width, format.height); + return getMaxInputSize(codecInfo, format.sampleMimeType, format.width, format.height); } } /** - * Returns a maximum input size for a given mime type, width and height. + * Returns a maximum input size for a given codec, mime type, width and height. * + * @param codecInfo Information about the {@link MediaCodec} being configured. * @param sampleMimeType The format mime type. * @param width The width in pixels. * @param height The height in pixels. * @return A maximum input size in bytes, or {@link Format#NO_VALUE} if a maximum could not be * determined. */ - private static int getMaxInputSize(String sampleMimeType, int width, int height) { + private static int getMaxInputSize( + MediaCodecInfo codecInfo, String sampleMimeType, int width, int height) { if (width == Format.NO_VALUE || height == Format.NO_VALUE) { // We can't infer a maximum input size without video dimensions. return Format.NO_VALUE; @@ -1101,9 +1152,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { minCompressionRatio = 2; break; case MimeTypes.VIDEO_H264: - if ("BRAVIA 4K 2015".equals(Util.MODEL)) { - // The Sony BRAVIA 4k TV has input buffers that are too small for the calculated 4k video - // maximum input size, so use the default value. + if ("BRAVIA 4K 2015".equals(Util.MODEL) // Sony Bravia 4K + || ("Amazon".equals(Util.MANUFACTURER) + && ("KFSOWI".equals(Util.MODEL) // Kindle Soho + || ("AFTS".equals(Util.MODEL) && codecInfo.secure)))) { // Fire TV Gen 2 + // Use the default value for cases where platform limitations may prevent buffers of the + // calculated maximum input size from being allocated. return Format.NO_VALUE; } // Round up width/height to an integer number of macroblocks. @@ -1163,42 +1217,179 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { return Util.SDK_INT <= 22 && "foster".equals(Util.DEVICE) && "NVIDIA".equals(Util.MANUFACTURER); } - /** - * Returns whether the device is known to implement {@link MediaCodec#setOutputSurface(Surface)} - * incorrectly. - *

    - * If true is returned then we fall back to releasing and re-instantiating the codec instead. + /* + * TODO: + * + * 1. Validate that Android device certification now ensures correct behavior, and add a + * corresponding SDK_INT upper bound for applying the workaround (probably SDK_INT < 26). + * 2. Determine a complete list of affected devices. + * 3. Some of the devices in this list only fail to support setOutputSurface when switching from + * a SurfaceView provided Surface to a Surface of another type (e.g. TextureView/DummySurface), + * and vice versa. One hypothesis is that setOutputSurface fails when the surfaces have + * different pixel formats. If we can find a way to query the Surface instances to determine + * whether this case applies, then we'll be able to provide a more targeted workaround. */ - private static boolean codecNeedsSetOutputSurfaceWorkaround(String name) { - // Work around https://github.com/google/ExoPlayer/issues/3236, + /** + * Returns whether the codec is known to implement {@link MediaCodec#setOutputSurface(Surface)} + * incorrectly. + * + *

    If true is returned then we fall back to releasing and re-instantiating the codec instead. + * + * @param name The name of the codec. + * @return True if the device is known to implement {@link MediaCodec#setOutputSurface(Surface)} + * incorrectly. + */ + protected boolean codecNeedsSetOutputSurfaceWorkaround(String name) { + if (Util.SDK_INT >= 27 || name.startsWith("OMX.google")) { + // Devices running API level 27 or later should also be unaffected. Google OMX decoders are + // not known to have this issue on any API level. + return false; + } + // Work around: + // https://github.com/google/ExoPlayer/issues/3236, // https://github.com/google/ExoPlayer/issues/3355, // https://github.com/google/ExoPlayer/issues/3439, // https://github.com/google/ExoPlayer/issues/3724, // https://github.com/google/ExoPlayer/issues/3835, // https://github.com/google/ExoPlayer/issues/4006, // https://github.com/google/ExoPlayer/issues/4084, - // https://github.com/google/ExoPlayer/issues/4104. - // https://github.com/google/ExoPlayer/issues/4134. - return (("deb".equals(Util.DEVICE) // Nexus 7 (2013) - || "flo".equals(Util.DEVICE) // Nexus 7 (2013) - || "mido".equals(Util.DEVICE) // Redmi Note 4 - || "santoni".equals(Util.DEVICE)) // Redmi 4X - && "OMX.qcom.video.decoder.avc".equals(name)) - || (("tcl_eu".equals(Util.DEVICE) // TCL Percee TV - || "SVP-DTV15".equals(Util.DEVICE) // Sony Bravia 4K 2015 - || "BRAVIA_ATV2".equals(Util.DEVICE) // Sony Bravia 4K GB - || Util.DEVICE.startsWith("panell_") // Motorola Moto C Plus - || "F3311".equals(Util.DEVICE) // Sony Xperia E5 - || "M5c".equals(Util.DEVICE) // Meizu M5C - || "QM16XE_U".equals(Util.DEVICE) // Philips QM163E - || "A7010a48".equals(Util.DEVICE) // Lenovo K4 Note - || "woods_f".equals(Util.MODEL)) // Moto E (4) - && "OMX.MTK.VIDEO.DECODER.AVC".equals(name)) - || (("ALE-L21".equals(Util.MODEL) // Huawei P8 Lite - || "CAM-L21".equals(Util.MODEL)) // Huawei Y6II - && "OMX.k3.video.decoder.avc".equals(name)) - || (("HUAWEI VNS-L21".equals(Util.MODEL)) // Huawei P9 Lite - && "OMX.IMG.MSVDX.Decoder.AVC".equals(name)); + // https://github.com/google/ExoPlayer/issues/4104, + // https://github.com/google/ExoPlayer/issues/4134, + // https://github.com/google/ExoPlayer/issues/4315, + // https://github.com/google/ExoPlayer/issues/4419, + // https://github.com/google/ExoPlayer/issues/4460, + // https://github.com/google/ExoPlayer/issues/4468. + synchronized (MediaCodecVideoRenderer.class) { + if (!evaluatedDeviceNeedsSetOutputSurfaceWorkaround) { + switch (Util.DEVICE) { + case "1601": + case "1713": + case "1714": + case "A10-70F": + case "A1601": + case "A2016a40": + case "A7000-a": + case "A7000plus": + case "A7010a48": + case "A7020a48": + case "AquaPowerM": + case "Aura_Note_2": + case "BLACK-1X": + case "BRAVIA_ATV2": + case "C1": + case "ComioS1": + case "CP8676_I02": + case "CPH1609": + case "CPY83_I00": + case "cv1": + case "cv3": + case "deb": + case "E5643": + case "ELUGA_A3_Pro": + case "ELUGA_Note": + case "ELUGA_Prim": + case "ELUGA_Ray_X": + case "EverStar_S": + case "F3111": + case "F3113": + case "F3116": + case "F3211": + case "F3213": + case "F3215": + case "F3311": + case "flo": + case "GiONEE_CBL7513": + case "GiONEE_GBL7319": + case "GIONEE_GBL7360": + case "GIONEE_SWW1609": + case "GIONEE_SWW1627": + case "GIONEE_SWW1631": + case "GIONEE_WBL5708": + case "GIONEE_WBL7365": + case "GIONEE_WBL7519": + case "griffin": + case "htc_e56ml_dtul": + case "hwALE-H": + case "HWBLN-H": + case "HWCAM-H": + case "HWVNS-H": + case "iball8735_9806": + case "Infinix-X572": + case "iris60": + case "itel_S41": + case "j2xlteins": + case "JGZ": + case "K50a40": + case "le_x6": + case "LS-5017": + case "M5c": + case "manning": + case "marino_f": + case "MEIZU_M5": + case "mh": + case "mido": + case "MX6": + case "namath": + case "nicklaus_f": + case "NX541J": + case "NX573J": + case "OnePlus5T": + case "p212": + case "P681": + case "P85": + case "panell_d": + case "panell_dl": + case "panell_ds": + case "panell_dt": + case "PB2-670M": + case "PGN528": + case "PGN610": + case "PGN611": + case "Phantom6": + case "Pixi4-7_3G": + case "Pixi5-10_4G": + case "PLE": + case "PRO7S": + case "Q350": + case "Q4260": + case "Q427": + case "Q4310": + case "Q5": + case "QM16XE_U": + case "QX1": + case "santoni": + case "Slate_Pro": + case "SVP-DTV15": + case "s905x018": + case "taido_row": + case "TB3-730F": + case "TB3-730X": + case "TB3-850F": + case "TB3-850M": + case "tcl_eu": + case "V1": + case "V23GB": + case "V5": + case "vernee_M5": + case "watson": + case "whyred": + case "woods_f": + case "woods_fn": + case "X3_HK": + case "XE2X": + case "XT1663": + case "Z12_PRO": + case "Z80": + deviceNeedsSetOutputSurfaceWorkaround = true; + break; + default: + // Workaround not required. + break; + } + evaluatedDeviceNeedsSetOutputSurfaceWorkaround = true; + } + } + return deviceNeedsSetOutputSurfaceWorkaround; } protected static final class CodecMaxValues { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoFrameReleaseTimeHelper.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 780198fe7..3c0fb9219 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; import android.annotation.TargetApi; import android.content.Context; @@ -26,8 +26,8 @@ import android.view.Choreographer; import android.view.Choreographer.FrameCallback; import android.view.Display; import android.view.WindowManager; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.util.Util; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; /** * Makes a best effort to adjust frame release timestamps for a smoother visual result. @@ -72,8 +72,12 @@ public final class VideoFrameReleaseTimeHelper { * @param context A context from which information about the default display can be retrieved. */ public VideoFrameReleaseTimeHelper(@Nullable Context context) { - windowManager = context == null ? null - : (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (context != null) { + context = context.getApplicationContext(); + windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + } else { + windowManager = null; + } if (windowManager != null) { displayListener = Util.SDK_INT >= 17 ? maybeBuildDefaultDisplayListenerV17(context) : null; vsyncSampler = VSyncSampler.getInstance(); @@ -287,7 +291,7 @@ public final class VideoFrameReleaseTimeHelper { sampledVsyncTimeNs = C.TIME_UNSET; choreographerOwnerThread = new HandlerThread("ChoreographerOwner:Handler"); choreographerOwnerThread.start(); - handler = new Handler(choreographerOwnerThread.getLooper(), this); + handler = Util.createHandler(choreographerOwnerThread.getLooper(), /* callback= */ this); handler.sendEmptyMessage(CREATE_CHOREOGRAPHER); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoListener.java similarity index 75% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoListener.java index 2af118ae5..07a6f98b2 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoListener.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; import android.graphics.SurfaceTexture; @@ -36,14 +36,27 @@ public interface VideoListener { * square pixels this will be equal to 1.0. Different values are indicative of anamorphic * content. */ - void onVideoSizeChanged( - int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio); + default void onVideoSizeChanged( + int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {} + + /** + * Called each time there's a change in the size of the surface onto which the video is being + * rendered. + * + * @param width The surface width in pixels. May be {@link + * com.google.android.exoplayer2.C#LENGTH_UNSET} if unknown, or 0 if the video is not rendered + * onto a surface. + * @param height The surface height in pixels. May be {@link + * com.google.android.exoplayer2.C#LENGTH_UNSET} if unknown, or 0 if the video is not rendered + * onto a surface. + */ + default void onSurfaceSizeChanged(int width, int height) {} /** * Called when a frame is rendered for the first time since setting the surface, and when a frame * is rendered for the first time since a video track was selected. */ - void onRenderedFirstFrame(); + default void onRenderedFirstFrame() {} boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture); void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoRendererEventListener.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoRendererEventListener.java rename to TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java index c76f661e9..d6ea0ebae 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/video/VideoRendererEventListener.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.telegram.messenger.exoplayer2.video; +package com.google.android.exoplayer2.video; import android.os.Handler; import android.os.SystemClock; import android.support.annotation.Nullable; import android.view.Surface; import android.view.TextureView; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.Renderer; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.decoder.DecoderCounters; +import com.google.android.exoplayer2.util.Assertions; /** * Listener of video {@link Renderer} events. diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java index fb336ca18..4860ca0c8 100755 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java @@ -16,8 +16,8 @@ public class SQLiteDatabase { private final long sqliteHandle; - private boolean isOpen = false; - private boolean inTransaction = false; + private boolean isOpen; + private boolean inTransaction; public long getSQLiteHandle() { return sqliteHandle; diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java index dcf540e20..e165d2bda 100755 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java @@ -18,7 +18,7 @@ public class SQLitePreparedStatement { private boolean isFinalized = false; private long sqliteStatementHandle; - private boolean finalizeAfterQuery = false; + private boolean finalizeAfterQuery; //private static HashMap hashMap; @@ -53,7 +53,8 @@ public class SQLitePreparedStatement { reset(sqliteStatementHandle); int i = 1; - for (Object obj : args) { + for (int a = 0; a < args.length; a++) { + Object obj = args[a]; if (obj == null) { bindNull(sqliteStatementHandle, i); } else if (obj instanceof Integer) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index f8930d05d..f1e8f6f06 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -15,11 +15,13 @@ import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -843,8 +845,25 @@ public class AndroidUtilities { return value; } + private static CallReceiver callReceiver; + public static void setWaitingForCall(boolean value) { synchronized (callLock) { + try { + if (value) { + if (callReceiver == null) { + final IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED); + ApplicationLoader.applicationContext.registerReceiver(callReceiver = new CallReceiver(), filter); + } + } else { + if (callReceiver != null) { + ApplicationLoader.applicationContext.unregisterReceiver(callReceiver); + callReceiver = null; + } + } + } catch (Exception ignore) { + + } waitingForCall = value; } } @@ -2244,4 +2263,12 @@ public class AndroidUtilities { }); builder.show(); } + + public static String getSystemProperty(String key){ + try{ + Class props=Class.forName("android.os.SystemProperties"); + return (String)props.getMethod("get", String.class).invoke(null, key); + }catch(Exception ignore){} + return null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 90406534e..6026b19fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -135,12 +135,7 @@ public class ApplicationLoader extends Application { applicationHandler = new Handler(applicationContext.getMainLooper()); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - startPushService(); - } - }); + AndroidUtilities.runOnUIThread(ApplicationLoader::startPushService); } public static void startPushService() { @@ -148,8 +143,8 @@ public class ApplicationLoader extends Application { if (preferences.getBoolean("pushService", true)) { try { applicationContext.startService(new Intent(applicationContext, NotificationsService.class)); - } catch (Throwable e) { - FileLog.e(e); + } catch (Throwable ignore) { + } } else { stopPushService(); @@ -176,38 +171,32 @@ public class ApplicationLoader extends Application { } private void initPlayServices() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (checkPlayServices()) { - final String currentPushString = SharedConfig.pushString; - if (!TextUtils.isEmpty(currentPushString)) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("GCM regId = " + currentPushString); - } - } else { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("GCM Registration not found."); - } + AndroidUtilities.runOnUIThread(() -> { + if (checkPlayServices()) { + final String currentPushString = SharedConfig.pushString; + if (!TextUtils.isEmpty(currentPushString)) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("GCM regId = " + currentPushString); } - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - String token = FirebaseInstanceId.getInstance().getToken(); - if (!TextUtils.isEmpty(token)) { - GcmInstanceIDListenerService.sendRegistrationToServer(token); - } - } catch (Throwable e) { - FileLog.e(e); - } - } - }); } else { if (BuildVars.LOGS_ENABLED) { - FileLog.d("No valid Google Play Services APK found."); + FileLog.d("GCM Registration not found."); } } + Utilities.globalQueue.postRunnable(() -> { + try { + String token = FirebaseInstanceId.getInstance().getToken(); + if (!TextUtils.isEmpty(token)) { + GcmInstanceIDListenerService.sendRegistrationToServer(token); + } + } catch (Throwable e) { + FileLog.e(e); + } + }); + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("No valid Google Play Services APK found."); + } } }, 1000); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 417d29e57..035346381 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -17,8 +17,8 @@ public class BuildVars { public static boolean DEBUG_PRIVATE_VERSION = false; public static boolean LOGS_ENABLED = false; public static boolean CHECK_UPDATES = false; - public static int BUILD_VERSION = 1340; - public static String BUILD_VERSION_STRING = "4.9.0"; + public static int BUILD_VERSION = 1358; + public static String BUILD_VERSION_STRING = "4.9.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"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java index 60f5ef921..2bd1ba437 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java @@ -19,7 +19,7 @@ public class CallReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { - if (intent.getAction().equals("android.intent.action.PHONE_STATE")) { + if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { String phoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (TelephonyManager.EXTRA_STATE_RINGING.equals(phoneState)) { String phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java index 8ff7e81cb..f597bec4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java @@ -12,7 +12,6 @@ import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Locale; @@ -162,12 +161,9 @@ public class Emoji { } final Bitmap finalBitmap = bitmap; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - emojiBmp[page][page2] = finalBitmap; - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.emojiDidLoaded); - } + AndroidUtilities.runOnUIThread(() -> { + emojiBmp[page][page2] = finalBitmap; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.emojiDidLoaded); }); } catch (Throwable x) { if (BuildVars.LOGS_ENABLED) { @@ -301,12 +297,9 @@ public class Emoji { return; } loadingEmoji[info.page][info.page2] = true; - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - loadEmoji(info.page, info.page2); - loadingEmoji[info.page][info.page2] = false; - } + Utilities.globalQueue.postRunnable(() -> { + loadEmoji(info.page, info.page2); + loadingEmoji[info.page][info.page2] = false; }); canvas.drawRect(getBounds(), placeholderPaint); return; @@ -526,7 +519,7 @@ public class Emoji { } public static class EmojiSpan extends ImageSpan { - private Paint.FontMetricsInt fontMetrics = null; + private Paint.FontMetricsInt fontMetrics; private int size = AndroidUtilities.dp(20); public EmojiSpan(EmojiDrawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) { @@ -602,24 +595,21 @@ public class Emoji { for (HashMap.Entry entry : emojiUseHistory.entrySet()) { recentEmoji.add(entry.getKey()); } - Collections.sort(recentEmoji, new Comparator() { - @Override - public int compare(String lhs, String rhs) { - Integer count1 = emojiUseHistory.get(lhs); - Integer count2 = emojiUseHistory.get(rhs); - if (count1 == null) { - count1 = 0; - } - if (count2 == null) { - count2 = 0; - } - if (count1 > count2) { - return -1; - } else if (count1 < count2) { - return 1; - } - return 0; + Collections.sort(recentEmoji, (lhs, rhs) -> { + Integer count1 = emojiUseHistory.get(lhs); + Integer count2 = emojiUseHistory.get(rhs); + if (count1 == null) { + count1 = 0; } + if (count2 == null) { + count2 = 0; + } + if (count1 > count2) { + return -1; + } else if (count1 < count2) { + return 1; + } + return 0; }); while (recentEmoji.size() > 50) { recentEmoji.remove(recentEmoji.size() - 1); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index c2493dec2..2921fa70d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -8,13 +8,13 @@ package org.telegram.messenger; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.TransferListener; - import android.text.TextUtils; import android.util.SparseArray; import android.util.SparseIntArray; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.TransferListener; + import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -952,7 +952,7 @@ public class FileLoader { return new File(dir, getAttachFileName(attach, ext)); } - public static FileStreamLoadOperation getStreamLoadOperation(TransferListener listener) { + public static FileStreamLoadOperation getStreamLoadOperation(TransferListener listener) { return new FileStreamLoadOperation(listener); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java index e365cecb8..21420ae55 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java @@ -10,10 +10,11 @@ package org.telegram.messenger; import android.net.Uri; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; + import org.telegram.tgnet.TLRPC; import java.io.EOFException; @@ -23,10 +24,11 @@ import java.util.concurrent.CountDownLatch; public class FileStreamLoadOperation implements DataSource { - private final TransferListener listener; + private final TransferListener listener; private FileLoadOperation loadOperation; private Uri uri; + private DataSpec dataSpec; private long bytesRemaining; private boolean opened; private int currentOffset; @@ -39,13 +41,14 @@ public class FileStreamLoadOperation implements DataSource { this(null); } - public FileStreamLoadOperation(TransferListener listener) { + public FileStreamLoadOperation(TransferListener listener) { this.listener = listener; } @Override public long open(DataSpec dataSpec) throws IOException { uri = dataSpec.uri; + this.dataSpec = dataSpec; currentAccount = Utilities.parseInt(uri.getQueryParameter("account")); document = new TLRPC.TL_document(); document.access_hash = Utilities.parseLong(uri.getQueryParameter("hash")); @@ -68,7 +71,7 @@ public class FileStreamLoadOperation implements DataSource { } opened = true; if (listener != null) { - listener.onTransferStart(this, dataSpec); + listener.onTransferStart(this, dataSpec, false); } file = new RandomAccessFile(loadOperation.getCurrentFile(), "r"); file.seek(currentOffset); @@ -101,7 +104,7 @@ public class FileStreamLoadOperation implements DataSource { currentOffset += availableLength; bytesRemaining -= availableLength; if (listener != null) { - listener.onBytesTransferred(this, availableLength); + listener.onBytesTransferred(this, dataSpec, false, availableLength); } } catch (Exception e) { throw new IOException(e); @@ -135,7 +138,7 @@ public class FileStreamLoadOperation implements DataSource { if (opened) { opened = false; if (listener != null) { - listener.onTransferEnd(this); + listener.onTransferEnd(this, dataSpec, false); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java index 16a795c22..c151d46e0 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java @@ -17,15 +17,12 @@ public class GcmInstanceIDListenerService extends FirebaseInstanceIdService { public void onTokenRefresh() { try { final String refreshedToken = FirebaseInstanceId.getInstance().getToken(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("Refreshed token: " + refreshedToken); - } - ApplicationLoader.postInitApplication(); - sendRegistrationToServer(refreshedToken); + AndroidUtilities.runOnUIThread(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Refreshed token: " + refreshedToken); } + ApplicationLoader.postInitApplication(); + sendRegistrationToServer(refreshedToken); }); } catch (Throwable e) { FileLog.e(e); @@ -33,23 +30,15 @@ public class GcmInstanceIDListenerService extends FirebaseInstanceIdService { } public static void sendRegistrationToServer(final String token) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SharedConfig.pushString = token; - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - UserConfig userConfig = UserConfig.getInstance(a); - userConfig.registeredForPush = false; - userConfig.saveConfig(false); - if (userConfig.getClientUserId() != 0) { - final int currentAccount = a; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).registerForPush(token); - } - }); - } + Utilities.stageQueue.postRunnable(() -> { + SharedConfig.pushString = token; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + UserConfig userConfig = UserConfig.getInstance(a); + userConfig.registeredForPush = false; + userConfig.saveConfig(false); + if (userConfig.getClientUserId() != 0) { + final int currentAccount = a; + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).registerForPush(token)); } } }); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 709dce036..7a3cb035c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -29,7 +29,6 @@ import android.util.SparseArray; import org.telegram.messenger.secretmedia.EncryptedFileInputStream; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedFileDrawable; @@ -124,17 +123,9 @@ public class ImageLoader { long currentTime = System.currentTimeMillis(); if (progress == 1 || lastProgressTime == 0 || lastProgressTime < currentTime - 500) { lastProgressTime = currentTime; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - fileProgresses.put(url, progress); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, url, progress); - } - }); - } + Utilities.stageQueue.postRunnable(() -> { + fileProgresses.put(url, progress); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, url, progress)); }); } } @@ -299,17 +290,9 @@ public class ImageLoader { long currentTime = System.currentTimeMillis(); if (progress == 1 || lastProgressTime == 0 || lastProgressTime < currentTime - 500) { lastProgressTime = currentTime; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - fileProgresses.put(cacheImage.url, progress); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, cacheImage.url, progress); - } - }); - } + Utilities.stageQueue.postRunnable(() -> { + fileProgresses.put(cacheImage.url, progress); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, cacheImage.url, progress)); }); } } @@ -330,11 +313,8 @@ public class ImageLoader { req.location = webFile.location; req.offset = 0; req.limit = 0; - ConnectionsManager.getInstance(cacheImage.currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(cacheImage.currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -476,49 +456,25 @@ public class ImageLoader { } else { httpFileLoadError(cacheImage.url); } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - fileProgresses.remove(cacheImage.url); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (result) { - NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidLoaded, cacheImage.url); - } else { - NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 2); - } - } - }); - } - }); - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - runHttpTasks(true); - } + Utilities.stageQueue.postRunnable(() -> { + fileProgresses.remove(cacheImage.url); + AndroidUtilities.runOnUIThread(() -> { + if (result) { + NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidLoaded, cacheImage.url); + } else { + NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 2); + } + }); }); + imageLoadQueue.postRunnable(() -> runHttpTasks(true)); } @Override protected void onCancelled() { - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - runHttpTasks(true); - } - }); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - fileProgresses.remove(cacheImage.url); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 1); - } - }); - } + imageLoadQueue.postRunnable(() -> runHttpTasks(true)); + Utilities.stageQueue.postRunnable(() -> { + fileProgresses.remove(cacheImage.url); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(cacheImage.currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 1)); }); } } @@ -542,12 +498,7 @@ public class ImageLoader { return; } final String name = FileLoader.getAttachFileName(thumbLocation); - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - thumbGenerateTasks.remove(name); - } - }); + imageLoadQueue.postRunnable(() -> thumbGenerateTasks.remove(name)); } @Override @@ -602,18 +553,15 @@ public class ImageLoader { FileLog.e(e); } final BitmapDrawable bitmapDrawable = new BitmapDrawable(originalBitmap); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - removeTask(); + AndroidUtilities.runOnUIThread(() -> { + removeTask(); - String kf = key; - if (filter != null) { - kf += "@" + filter; - } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.messageThumbGenerated, bitmapDrawable, kf); - memCache.put(kf, bitmapDrawable); + String kf = key; + if (filter != null) { + kf += "@" + filter; } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.messageThumbGenerated, bitmapDrawable, kf); + memCache.put(kf, bitmapDrawable); }); } catch (Throwable e) { FileLog.e(e); @@ -1040,30 +988,22 @@ public class ImageLoader { } private void onPostExecute(final BitmapDrawable bitmapDrawable) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - BitmapDrawable toSet = null; - if (bitmapDrawable instanceof AnimatedFileDrawable) { + AndroidUtilities.runOnUIThread(() -> { + BitmapDrawable toSet = null; + if (bitmapDrawable instanceof AnimatedFileDrawable) { + toSet = bitmapDrawable; + } else if (bitmapDrawable != null) { + toSet = memCache.get(cacheImage.key); + if (toSet == null) { + memCache.put(cacheImage.key, bitmapDrawable); toSet = bitmapDrawable; - } else if (bitmapDrawable != null) { - toSet = memCache.get(cacheImage.key); - if (toSet == null) { - memCache.put(cacheImage.key, bitmapDrawable); - toSet = bitmapDrawable; - } else { - Bitmap image = bitmapDrawable.getBitmap(); - image.recycle(); - } + } else { + Bitmap image = bitmapDrawable.getBitmap(); + image.recycle(); } - final BitmapDrawable toSetFinal = toSet; - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - cacheImage.setImageAndClear(toSetFinal); - } - }); } + final BitmapDrawable toSetFinal = toSet; + imageLoadQueue.postRunnable(() -> cacheImage.setImageAndClear(toSetFinal)); }); } @@ -1192,27 +1132,24 @@ public class ImageLoader { public void setImageAndClear(final BitmapDrawable image) { if (image != null) { final ArrayList finalImageReceiverArray = new ArrayList<>(imageReceiverArray); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (image instanceof AnimatedFileDrawable) { - boolean imageSet = false; - AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) image; - for (int a = 0; a < finalImageReceiverArray.size(); a++) { - ImageReceiver imgView = finalImageReceiverArray.get(a); - if (imgView.setImageBitmapByKey(a == 0 ? fileDrawable : fileDrawable.makeCopy(), key, selfThumb, false)) { - imageSet = true; - } - } - if (!imageSet) { - ((AnimatedFileDrawable) image).recycle(); - } - } else { - for (int a = 0; a < finalImageReceiverArray.size(); a++) { - ImageReceiver imgView = finalImageReceiverArray.get(a); - imgView.setImageBitmapByKey(image, key, selfThumb, false); + AndroidUtilities.runOnUIThread(() -> { + if (image instanceof AnimatedFileDrawable) { + boolean imageSet = false; + AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) image; + for (int a = 0; a < finalImageReceiverArray.size(); a++) { + ImageReceiver imgView = finalImageReceiverArray.get(a); + if (imgView.setImageBitmapByKey(a == 0 ? fileDrawable : fileDrawable.makeCopy(), key, selfThumb, false)) { + imageSet = true; } } + if (!imageSet) { + ((AnimatedFileDrawable) image).recycle(); + } + } else { + for (int a = 0; a < finalImageReceiverArray.size(); a++) { + ImageReceiver imgView = finalImageReceiverArray.get(a); + imgView.setImageBitmapByKey(image, key, selfThumb, false); + } } }); } @@ -1297,73 +1234,46 @@ public class ImageLoader { if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) { lastProgressUpdateTime = currentTime; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted)); } } @Override public void fileDidUploaded(final String location, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile, final byte[] key, final byte[] iv, final long totalFileSize) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidUpload, location, inputFile, inputEncryptedFile, key, iv, totalFileSize); - } - }); - fileProgresses.remove(location); - } + Utilities.stageQueue.postRunnable(() -> { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidUpload, location, inputFile, inputEncryptedFile, key, iv, totalFileSize)); + fileProgresses.remove(location); }); } @Override public void fileDidFailedUpload(final String location, final boolean isEncrypted) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidFailUpload, location, isEncrypted); - } - }); - fileProgresses.remove(location); - } + Utilities.stageQueue.postRunnable(() -> { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidFailUpload, location, isEncrypted)); + fileProgresses.remove(location); }); } @Override public void fileDidLoaded(final String location, final File finalFile, final int type) { fileProgresses.remove(location); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (SharedConfig.saveToGallery && telegramPath != null && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { - if (finalFile.toString().startsWith(telegramPath.toString())) { - AndroidUtilities.addMediaToGallery(finalFile.toString()); - } + AndroidUtilities.runOnUIThread(() -> { + if (SharedConfig.saveToGallery && telegramPath != null && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + if (finalFile.toString().startsWith(telegramPath.toString())) { + AndroidUtilities.addMediaToGallery(finalFile.toString()); } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidLoaded, location); - ImageLoader.this.fileDidLoaded(location, finalFile, type); } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidLoaded, location); + ImageLoader.this.fileDidLoaded(location, finalFile, type); }); } @Override public void fileDidFailedLoad(final String location, final int canceled) { fileProgresses.remove(location); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - ImageLoader.this.fileDidFailedLoad(location, canceled); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, location, canceled); - } + AndroidUtilities.runOnUIThread(() -> { + ImageLoader.this.fileDidFailedLoad(location, canceled); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileDidFailedLoad, location, canceled); }); } @@ -1373,12 +1283,7 @@ public class ImageLoader { long currentTime = System.currentTimeMillis(); if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) { lastProgressUpdateTime = currentTime; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress)); } } }); @@ -1391,11 +1296,7 @@ public class ImageLoader { if (BuildVars.LOGS_ENABLED) { FileLog.d("file system changed"); } - Runnable r = new Runnable() { - public void run() { - checkMediaPaths(); - } - }; + Runnable r = () -> checkMediaPaths(); if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { AndroidUtilities.runOnUIThread(r, 1000); } else { @@ -1425,17 +1326,9 @@ public class ImageLoader { } public void checkMediaPaths() { - cacheOutQueue.postRunnable(new Runnable() { - @Override - public void run() { - final SparseArray paths = createMediaPaths(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - FileLoader.setMediaDirs(paths); - } - }); - } + cacheOutQueue.postRunnable(() -> { + final SparseArray paths = createMediaPaths(); + AndroidUtilities.runOnUIThread(() -> FileLoader.setMediaDirs(paths)); }); } @@ -1685,26 +1578,23 @@ public class ImageLoader { if (imageReceiver == null) { return; } - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - int start = 0; - int count = 2; - if (type == 1) { - count = 1; - } else if (type == 2) { - start = 1; + imageLoadQueue.postRunnable(() -> { + int start = 0; + int count = 2; + if (type == 1) { + count = 1; + } else if (type == 2) { + start = 1; + } + for (int a = start; a < count; a++) { + int TAG = imageReceiver.getTag(a == 0); + if (a == 0) { + removeFromWaitingForThumb(TAG); } - for (int a = start; a < count; a++) { - int TAG = imageReceiver.getTag(a == 0); - if (a == 0) { - removeFromWaitingForThumb(TAG); - } - if (TAG != 0) { - CacheImage ei = imageLoadingByTag.get(TAG); - if (ei != null) { - ei.removeImageReceiver(imageReceiver); - } + if (TAG != 0) { + CacheImage ei = imageLoadingByTag.get(TAG); + if (ei != null) { + ei.removeImageReceiver(imageReceiver); } } } @@ -1765,12 +1655,7 @@ public class ImageLoader { public void replaceImageInCache(final String oldKey, final String newKey, final TLRPC.FileLocation newLocation, boolean post) { if (post) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - replaceImageInCacheInternal(oldKey, newKey, newLocation); - } - }); + AndroidUtilities.runOnUIThread(() -> replaceImageInCacheInternal(oldKey, newKey, newLocation)); } else { replaceImageInCacheInternal(oldKey, newKey, newLocation); } @@ -1800,12 +1685,7 @@ public class ImageLoader { if (key == null) { return; } - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - forceLoadingImages.remove(key); - } - }); + imageLoadQueue.postRunnable(() -> forceLoadingImages.remove(key)); } private void createLoadOperationForImageReceiver(final ImageReceiver imageReceiver, final String key, final String url, final String ext, final TLObject imageLocation, final String httpLocation, final String filter, final int size, final int cacheType, final int thumb) { @@ -1826,187 +1706,184 @@ public class ImageLoader { final MessageObject parentMessageObject = imageReceiver.getParentMessageObject(); final boolean shouldGenerateQualityThumb = imageReceiver.isShouldGenerateQualityThumb(); final int currentAccount = imageReceiver.getcurrentAccount(); - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - boolean added = false; - if (thumb != 2) { - CacheImage alreadyLoadingUrl = imageLoadingByUrl.get(url); - CacheImage alreadyLoadingCache = imageLoadingByKeys.get(key); - CacheImage alreadyLoadingImage = imageLoadingByTag.get(finalTag); - if (alreadyLoadingImage != null) { - if (alreadyLoadingImage == alreadyLoadingCache) { - added = true; - } else if (alreadyLoadingImage == alreadyLoadingUrl) { - if (alreadyLoadingCache == null) { - alreadyLoadingImage.replaceImageReceiver(imageReceiver, key, filter, thumb != 0); - } - added = true; - } else { - alreadyLoadingImage.removeImageReceiver(imageReceiver); + imageLoadQueue.postRunnable(() -> { + boolean added = false; + if (thumb != 2) { + CacheImage alreadyLoadingUrl = imageLoadingByUrl.get(url); + CacheImage alreadyLoadingCache = imageLoadingByKeys.get(key); + CacheImage alreadyLoadingImage = imageLoadingByTag.get(finalTag); + if (alreadyLoadingImage != null) { + if (alreadyLoadingImage == alreadyLoadingCache) { + added = true; + } else if (alreadyLoadingImage == alreadyLoadingUrl) { + if (alreadyLoadingCache == null) { + alreadyLoadingImage.replaceImageReceiver(imageReceiver, key, filter, thumb != 0); } - } - - if (!added && alreadyLoadingCache != null) { - alreadyLoadingCache.addImageReceiver(imageReceiver, key, filter, thumb != 0); - added = true; - } - if (!added && alreadyLoadingUrl != null) { - alreadyLoadingUrl.addImageReceiver(imageReceiver, key, filter, thumb != 0); added = true; + } else { + alreadyLoadingImage.removeImageReceiver(imageReceiver); } } - if (!added) { - boolean onlyCache = false; - boolean isQuality = false; - File cacheFile = null; - boolean cacheFileExists = false; + if (!added && alreadyLoadingCache != null) { + alreadyLoadingCache.addImageReceiver(imageReceiver, key, filter, thumb != 0); + added = true; + } + if (!added && alreadyLoadingUrl != null) { + alreadyLoadingUrl.addImageReceiver(imageReceiver, key, filter, thumb != 0); + added = true; + } + } - if (httpLocation != null) { - if (!httpLocation.startsWith("http")) { - onlyCache = true; - if (httpLocation.startsWith("thumb://")) { - int idx = httpLocation.indexOf(":", 8); - if (idx >= 0) { - cacheFile = new File(httpLocation.substring(idx + 1)); - } - } else if (httpLocation.startsWith("vthumb://")) { - int idx = httpLocation.indexOf(":", 9); - if (idx >= 0) { - cacheFile = new File(httpLocation.substring(idx + 1)); - } - } else { - cacheFile = new File(httpLocation); - } - } - } else if (thumb != 0) { - if (finalIsNeedsQualityThumb) { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + url); - if (!cacheFile.exists()) { - cacheFile = null; - } else { - cacheFileExists = true; - } - } + if (!added) { + boolean onlyCache = false; + boolean isQuality = false; + File cacheFile = null; + boolean cacheFileExists = false; - if (parentMessageObject != null) { - File attachPath = null; - if (parentMessageObject.messageOwner.attachPath != null && parentMessageObject.messageOwner.attachPath.length() > 0) { - attachPath = new File(parentMessageObject.messageOwner.attachPath); - if (!attachPath.exists()) { - attachPath = null; - } + if (httpLocation != null) { + if (!httpLocation.startsWith("http")) { + onlyCache = true; + if (httpLocation.startsWith("thumb://")) { + int idx = httpLocation.indexOf(":", 8); + if (idx >= 0) { + cacheFile = new File(httpLocation.substring(idx + 1)); } - if (attachPath == null) { - attachPath = FileLoader.getPathToMessage(parentMessageObject.messageOwner); - } - if (finalIsNeedsQualityThumb && cacheFile == null) { - String location = parentMessageObject.getFileName(); - ThumbGenerateInfo info = waitingForQualityThumb.get(location); - if (info == null) { - info = new ThumbGenerateInfo(); - info.fileLocation = (TLRPC.FileLocation) imageLocation; - info.filter = filter; - waitingForQualityThumb.put(location, info); - } - info.count++; - waitingForQualityThumbByTag.put(finalTag, location); - } - if (attachPath.exists() && shouldGenerateQualityThumb) { - generateThumb(parentMessageObject.getFileType(), attachPath, (TLRPC.FileLocation) imageLocation, filter); + } else if (httpLocation.startsWith("vthumb://")) { + int idx = httpLocation.indexOf(":", 9); + if (idx >= 0) { + cacheFile = new File(httpLocation.substring(idx + 1)); } + } else { + cacheFile = new File(httpLocation); + } + } + } else if (thumb != 0) { + if (finalIsNeedsQualityThumb) { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + url); + if (!cacheFile.exists()) { + cacheFile = null; + } else { + cacheFileExists = true; } } - 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")) { - String trueExt = getHttpUrlExtension(httpLocation, "jpg"); - if (trueExt.equals("mp4") || trueExt.equals("gif")) { - img.animatedFile = true; + if (parentMessageObject != null) { + File attachPath = null; + if (parentMessageObject.messageOwner.attachPath != null && parentMessageObject.messageOwner.attachPath.length() > 0) { + attachPath = new File(parentMessageObject.messageOwner.attachPath); + if (!attachPath.exists()) { + attachPath = null; } - } else if (imageLocation instanceof WebFile && MessageObject.isGifDocument((WebFile) imageLocation) || - imageLocation instanceof TLRPC.Document && (MessageObject.isGifDocument((TLRPC.Document) imageLocation) || MessageObject.isRoundVideoDocument((TLRPC.Document) imageLocation))) { + } + if (attachPath == null) { + attachPath = FileLoader.getPathToMessage(parentMessageObject.messageOwner); + } + if (finalIsNeedsQualityThumb && cacheFile == null) { + String location = parentMessageObject.getFileName(); + ThumbGenerateInfo info = waitingForQualityThumb.get(location); + if (info == null) { + info = new ThumbGenerateInfo(); + info.fileLocation = (TLRPC.FileLocation) imageLocation; + info.filter = filter; + waitingForQualityThumb.put(location, info); + } + info.count++; + waitingForQualityThumbByTag.put(finalTag, location); + } + if (attachPath.exists() && shouldGenerateQualityThumb) { + generateThumb(parentMessageObject.getFileType(), attachPath, (TLRPC.FileLocation) imageLocation, filter); + } + } + } + + 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")) { + String trueExt = getHttpUrlExtension(httpLocation, "jpg"); + if (trueExt.equals("mp4") || trueExt.equals("gif")) { img.animatedFile = true; } + } else if (imageLocation instanceof WebFile && MessageObject.isGifDocument((WebFile) imageLocation) || + imageLocation instanceof TLRPC.Document && (MessageObject.isGifDocument((TLRPC.Document) imageLocation) || MessageObject.isRoundVideoDocument((TLRPC.Document) imageLocation))) { + img.animatedFile = true; + } - if (cacheFile == null) { - if (imageLocation instanceof SecureDocument) { - img.secureDocument = (SecureDocument) imageLocation; - onlyCache = img.secureDocument.secureFile.dc_id == Integer.MIN_VALUE; - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url); - } else if (cacheType != 0 || size <= 0 || httpLocation != null || isEncrypted) { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url); - if (cacheFile.exists()) { - cacheFileExists = true; - } else if (cacheType == 2) { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url + ".enc"); - } - } else if (imageLocation instanceof TLRPC.Document) { - if (MessageObject.isVideoDocument((TLRPC.Document) imageLocation)) { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_VIDEO), url); - } else { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), url); - } - } else if (imageLocation instanceof WebFile) { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), url); - } else { - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE), url); + if (cacheFile == null) { + if (imageLocation instanceof SecureDocument) { + img.secureDocument = (SecureDocument) imageLocation; + onlyCache = img.secureDocument.secureFile.dc_id == Integer.MIN_VALUE; + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url); + } else if (cacheType != 0 || size <= 0 || httpLocation != null || isEncrypted) { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url); + if (cacheFile.exists()) { + cacheFileExists = true; + } else if (cacheType == 2) { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url + ".enc"); } - } - - img.selfThumb = thumb != 0; - img.key = key; - img.filter = filter; - img.httpUrl = httpLocation; - img.ext = ext; - img.currentAccount = currentAccount; - if (cacheType == 2) { - img.encryptionKeyPath = new File(FileLoader.getInternalCacheDir(), url + ".enc.key"); - } - img.addImageReceiver(imageReceiver, key, filter, thumb != 0); - if (onlyCache || cacheFileExists || cacheFile.exists()) { - img.finalFilePath = cacheFile; - img.cacheTask = new CacheOutTask(img); - imageLoadingByKeys.put(key, img); - if (thumb != 0) { - cacheThumbOutQueue.postRunnable(img.cacheTask); + } else if (imageLocation instanceof TLRPC.Document) { + if (MessageObject.isVideoDocument((TLRPC.Document) imageLocation)) { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_VIDEO), url); } else { - cacheOutQueue.postRunnable(img.cacheTask); + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), url); + } + } else if (imageLocation instanceof WebFile) { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), url); + } else { + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE), url); + } + } + + img.selfThumb = thumb != 0; + img.key = key; + img.filter = filter; + img.httpUrl = httpLocation; + img.ext = ext; + img.currentAccount = currentAccount; + if (cacheType == 2) { + img.encryptionKeyPath = new File(FileLoader.getInternalCacheDir(), url + ".enc.key"); + } + img.addImageReceiver(imageReceiver, key, filter, thumb != 0); + if (onlyCache || cacheFileExists || cacheFile.exists()) { + img.finalFilePath = cacheFile; + img.cacheTask = new CacheOutTask(img); + imageLoadingByKeys.put(key, img); + if (thumb != 0) { + cacheThumbOutQueue.postRunnable(img.cacheTask); + } else { + cacheOutQueue.postRunnable(img.cacheTask); + } + } else { + img.url = url; + img.location = imageLocation; + imageLoadingByUrl.put(url, img); + if (httpLocation == null) { + if (imageLocation instanceof TLRPC.FileLocation) { + TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation; + int localCacheType = cacheType; + if (localCacheType == 0 && (size <= 0 || location.key != null)) { + localCacheType = 1; + } + FileLoader.getInstance(currentAccount).loadFile(location, ext, size, localCacheType); + } else if (imageLocation instanceof TLRPC.Document) { + FileLoader.getInstance(currentAccount).loadFile((TLRPC.Document) imageLocation, true, cacheType); + } else if (imageLocation instanceof SecureDocument) { + FileLoader.getInstance(currentAccount).loadFile((SecureDocument) imageLocation, true); + } else if (imageLocation instanceof WebFile) { + FileLoader.getInstance(currentAccount).loadFile((WebFile) imageLocation, true, cacheType); + } + if (imageReceiver.isForceLoding()) { + forceLoadingImages.put(img.key, 0); } } else { - img.url = url; - img.location = imageLocation; - imageLoadingByUrl.put(url, img); - if (httpLocation == null) { - if (imageLocation instanceof TLRPC.FileLocation) { - TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation; - int localCacheType = cacheType; - if (localCacheType == 0 && (size <= 0 || location.key != null)) { - localCacheType = 1; - } - FileLoader.getInstance(currentAccount).loadFile(location, ext, size, localCacheType); - } else if (imageLocation instanceof TLRPC.Document) { - FileLoader.getInstance(currentAccount).loadFile((TLRPC.Document) imageLocation, true, cacheType); - } else if (imageLocation instanceof SecureDocument) { - FileLoader.getInstance(currentAccount).loadFile((SecureDocument) imageLocation, true); - } else if (imageLocation instanceof WebFile) { - FileLoader.getInstance(currentAccount).loadFile((WebFile) imageLocation, true, cacheType); - } - if (imageReceiver.isForceLoding()) { - forceLoadingImages.put(img.key, 0); - } - } else { - String file = Utilities.MD5(httpLocation); - File cacheDir = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); - img.tempFilePath = new File(cacheDir, file + "_temp.jpg"); - img.finalFilePath = cacheFile; - img.httpTask = new HttpImageTask(img, size); - httpTasks.add(img.httpTask); - runHttpTasks(false); - } + String file = Utilities.MD5(httpLocation); + File cacheDir = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); + img.tempFilePath = new File(cacheDir, file + "_temp.jpg"); + img.finalFilePath = cacheFile; + img.httpTask = new HttpImageTask(img, size); + httpTasks.add(img.httpTask); + runHttpTasks(false); } } } @@ -2149,67 +2026,61 @@ public class ImageLoader { } private void httpFileLoadError(final String location) { - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - CacheImage img = imageLoadingByUrl.get(location); - if (img == null) { - return; - } - HttpImageTask oldTask = img.httpTask; - img.httpTask = new HttpImageTask(oldTask.cacheImage, oldTask.imageSize); - httpTasks.add(img.httpTask); - runHttpTasks(false); + imageLoadQueue.postRunnable(() -> { + CacheImage img = imageLoadingByUrl.get(location); + if (img == null) { + return; } + HttpImageTask oldTask = img.httpTask; + img.httpTask = new HttpImageTask(oldTask.cacheImage, oldTask.imageSize); + httpTasks.add(img.httpTask); + runHttpTasks(false); }); } private void fileDidLoaded(final String location, final File finalFile, final int type) { - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - ThumbGenerateInfo info = waitingForQualityThumb.get(location); - if (info != null) { - generateThumb(type, finalFile, info.fileLocation, info.filter); - waitingForQualityThumb.remove(location); + imageLoadQueue.postRunnable(() -> { + ThumbGenerateInfo info = waitingForQualityThumb.get(location); + if (info != null) { + generateThumb(type, finalFile, info.fileLocation, info.filter); + waitingForQualityThumb.remove(location); + } + CacheImage img = imageLoadingByUrl.get(location); + if (img == null) { + return; + } + imageLoadingByUrl.remove(location); + ArrayList tasks = new ArrayList<>(); + for (int a = 0; a < img.imageReceiverArray.size(); a++) { + String key = img.keys.get(a); + String filter = img.filters.get(a); + Boolean thumb = img.thumbs.get(a); + ImageReceiver imageReceiver = img.imageReceiverArray.get(a); + CacheImage cacheImage = imageLoadingByKeys.get(key); + if (cacheImage == null) { + cacheImage = new CacheImage(); + cacheImage.secureDocument = img.secureDocument; + cacheImage.currentAccount = img.currentAccount; + cacheImage.finalFilePath = finalFile; + cacheImage.key = key; + cacheImage.httpUrl = img.httpUrl; + cacheImage.selfThumb = thumb; + cacheImage.ext = img.ext; + cacheImage.encryptionKeyPath = img.encryptionKeyPath; + cacheImage.cacheTask = new CacheOutTask(cacheImage); + cacheImage.filter = filter; + cacheImage.animatedFile = img.animatedFile; + imageLoadingByKeys.put(key, cacheImage); + tasks.add(cacheImage.cacheTask); } - CacheImage img = imageLoadingByUrl.get(location); - if (img == null) { - return; - } - imageLoadingByUrl.remove(location); - ArrayList tasks = new ArrayList<>(); - for (int a = 0; a < img.imageReceiverArray.size(); a++) { - String key = img.keys.get(a); - String filter = img.filters.get(a); - Boolean thumb = img.thumbs.get(a); - ImageReceiver imageReceiver = img.imageReceiverArray.get(a); - CacheImage cacheImage = imageLoadingByKeys.get(key); - if (cacheImage == null) { - cacheImage = new CacheImage(); - cacheImage.secureDocument = img.secureDocument; - cacheImage.currentAccount = img.currentAccount; - cacheImage.finalFilePath = finalFile; - cacheImage.key = key; - cacheImage.httpUrl = img.httpUrl; - cacheImage.selfThumb = thumb; - cacheImage.ext = img.ext; - cacheImage.encryptionKeyPath = img.encryptionKeyPath; - cacheImage.cacheTask = new CacheOutTask(cacheImage); - cacheImage.filter = filter; - cacheImage.animatedFile = img.animatedFile; - imageLoadingByKeys.put(key, cacheImage); - tasks.add(cacheImage.cacheTask); - } - cacheImage.addImageReceiver(imageReceiver, key, filter, thumb); - } - for (int a = 0; a < tasks.size(); a++) { - CacheOutTask task = tasks.get(a); - if (task.cacheImage.selfThumb) { - cacheThumbOutQueue.postRunnable(task); - } else { - cacheOutQueue.postRunnable(task); - } + cacheImage.addImageReceiver(imageReceiver, key, filter, thumb); + } + for (int a = 0; a < tasks.size(); a++) { + CacheOutTask task = tasks.get(a); + if (task.cacheImage.selfThumb) { + cacheThumbOutQueue.postRunnable(task); + } else { + cacheOutQueue.postRunnable(task); } } }); @@ -2219,13 +2090,10 @@ public class ImageLoader { if (canceled == 1) { return; } - imageLoadQueue.postRunnable(new Runnable() { - @Override - public void run() { - CacheImage img = imageLoadingByUrl.get(location); - if (img != null) { - img.setImageAndClear(null); - } + imageLoadQueue.postRunnable(() -> { + CacheImage img = imageLoadingByUrl.get(location); + if (img != null) { + img.setImageAndClear(null); } }); } @@ -2274,41 +2142,35 @@ public class ImageLoader { } private void runHttpFileLoadTasks(final HttpFileTask oldTask, final int reason) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (oldTask != null) { - currentHttpFileLoadTasksCount--; - } - if (oldTask != null) { - if (reason == 1) { - if (oldTask.canRetry) { - final HttpFileTask newTask = new HttpFileTask(oldTask.url, oldTask.tempFile, oldTask.ext, oldTask.currentAccount); - Runnable runnable = new Runnable() { - @Override - public void run() { - httpFileLoadTasks.add(newTask); - runHttpFileLoadTasks(null, 0); - } - }; - retryHttpsTasks.put(oldTask.url, runnable); - AndroidUtilities.runOnUIThread(runnable, 1000); - } else { - httpFileLoadTasksByKeys.remove(oldTask.url); - NotificationCenter.getInstance(oldTask.currentAccount).postNotificationName(NotificationCenter.httpFileDidFailedLoad, oldTask.url, 0); - } - } else if (reason == 2) { + AndroidUtilities.runOnUIThread(() -> { + if (oldTask != null) { + currentHttpFileLoadTasksCount--; + } + if (oldTask != null) { + if (reason == 1) { + if (oldTask.canRetry) { + final HttpFileTask newTask = new HttpFileTask(oldTask.url, oldTask.tempFile, oldTask.ext, oldTask.currentAccount); + Runnable runnable = () -> { + httpFileLoadTasks.add(newTask); + runHttpFileLoadTasks(null, 0); + }; + retryHttpsTasks.put(oldTask.url, runnable); + AndroidUtilities.runOnUIThread(runnable, 1000); + } else { httpFileLoadTasksByKeys.remove(oldTask.url); - File file = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(oldTask.url) + "." + oldTask.ext); - String result = oldTask.tempFile.renameTo(file) ? file.toString() : oldTask.tempFile.toString(); - NotificationCenter.getInstance(oldTask.currentAccount).postNotificationName(NotificationCenter.httpFileDidLoaded, oldTask.url, result); + NotificationCenter.getInstance(oldTask.currentAccount).postNotificationName(NotificationCenter.httpFileDidFailedLoad, oldTask.url, 0); } + } else if (reason == 2) { + httpFileLoadTasksByKeys.remove(oldTask.url); + File file = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(oldTask.url) + "." + oldTask.ext); + String result = oldTask.tempFile.renameTo(file) ? file.toString() : oldTask.tempFile.toString(); + NotificationCenter.getInstance(oldTask.currentAccount).postNotificationName(NotificationCenter.httpFileDidLoaded, oldTask.url, result); } - while (currentHttpFileLoadTasksCount < 2 && !httpFileLoadTasks.isEmpty()) { - HttpFileTask task = httpFileLoadTasks.poll(); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); - currentHttpFileLoadTasksCount++; - } + } + while (currentHttpFileLoadTasksCount < 2 && !httpFileLoadTasks.isEmpty()) { + HttpFileTask task = httpFileLoadTasks.poll(); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); + currentHttpFileLoadTasksCount++; } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 00264938a..f88639c87 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -21,7 +21,6 @@ import android.util.Xml; import org.telegram.messenger.time.FastDateFormat; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.xmlpull.v1.XmlPullParser; @@ -80,12 +79,9 @@ public class LocaleController { private class TimeZoneChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - ApplicationLoader.applicationHandler.post(new Runnable() { - @Override - public void run() { - if (!formatterMonth.getTimeZone().equals(TimeZone.getDefault())) { - LocaleController.getInstance().recreateFormatters(); - } + ApplicationLoader.applicationHandler.post(() -> { + if (!formatterMonth.getTimeZone().equals(TimeZone.getDefault())) { + LocaleController.getInstance().recreateFormatters(); } }); } @@ -270,12 +266,7 @@ public class LocaleController { loadOtherLanguages(); if (remoteLanguages.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadRemoteLanguages(UserConfig.selectedAccount); - } - }); + AndroidUtilities.runOnUIThread(() -> loadRemoteLanguages(UserConfig.selectedAccount)); } for (int a = 0; a < otherLanguages.size(); a++) { @@ -717,12 +708,7 @@ public class LocaleController { FileLog.d("reload locale because file doesn't exist " + pathToFile); } if (init) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - applyRemoteLanguage(localeInfo, true, currentAccount); - } - }); + AndroidUtilities.runOnUIThread(() -> applyRemoteLanguage(localeInfo, true, currentAccount)); } else { applyRemoteLanguage(localeInfo, true, currentAccount); } @@ -765,12 +751,7 @@ public class LocaleController { changingConfiguration = false; if (reloadLastFile) { if (init) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - reloadCurrentRemoteLocale(currentAccount); - } - }); + AndroidUtilities.runOnUIThread(() -> reloadCurrentRemoteLocale(currentAccount)); } else { reloadCurrentRemoteLocale(currentAccount); } @@ -806,6 +787,17 @@ public class LocaleController { return value; } + public static String getServerString(String key) { + String value = getInstance().localeValues.get(key); + if (value == null) { + int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(key, "string", ApplicationLoader.applicationContext.getPackageName()); + if (resourceId != 0) { + value = ApplicationLoader.applicationContext.getString(resourceId); + } + } + return value; + } + public static String getString(String key, int res) { return getInstance().getStringInternal(key, res); } @@ -1451,55 +1443,52 @@ public class LocaleController { writer.write(""); writer.close(); final HashMap valuesToSet = getLocaleFileStrings(finalFile); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - LocaleInfo localeInfo = getLanguageFromDict(langCode); - if (localeInfo != null) { - localeInfo.version = difference.version; + AndroidUtilities.runOnUIThread(() -> { + LocaleInfo localeInfo = getLanguageFromDict(langCode); + if (localeInfo != null) { + localeInfo.version = difference.version; + } + saveOtherLanguages(); + if (currentLocaleInfo != null && currentLocaleInfo.isLocal()) { + return; + } + try { + Locale newLocale; + String[] args = localeInfo.shortName.split("_"); + if (args.length == 1) { + newLocale = new Locale(localeInfo.shortName); + } else { + newLocale = new Locale(args[0], args[1]); } - saveOtherLanguages(); - if (currentLocaleInfo != null && currentLocaleInfo.isLocal()) { - return; - } - try { - Locale newLocale; - String[] args = localeInfo.shortName.split("_"); - if (args.length == 1) { - newLocale = new Locale(localeInfo.shortName); - } else { - newLocale = new Locale(args[0], args[1]); - } - if (newLocale != null) { - languageOverride = localeInfo.shortName; + if (newLocale != null) { + languageOverride = localeInfo.shortName; - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - SharedPreferences.Editor editor = preferences.edit(); - editor.putString("language", localeInfo.getKey()); - editor.commit(); + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("language", localeInfo.getKey()); + editor.commit(); + } + if (newLocale != null) { + localeValues = valuesToSet; + currentLocale = newLocale; + currentLocaleInfo = localeInfo; + currentPluralRules = allRules.get(currentLocale.getLanguage()); + if (currentPluralRules == null) { + currentPluralRules = allRules.get("en"); } - if (newLocale != null) { - localeValues = valuesToSet; - currentLocale = newLocale; - currentLocaleInfo = localeInfo; - currentPluralRules = allRules.get(currentLocale.getLanguage()); - if (currentPluralRules == null) { - currentPluralRules = allRules.get("en"); - } - changingConfiguration = true; - Locale.setDefault(currentLocale); - android.content.res.Configuration config = new android.content.res.Configuration(); - config.locale = currentLocale; - ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); - changingConfiguration = false; - } - } catch (Exception e) { - FileLog.e(e); + changingConfiguration = true; + Locale.setDefault(currentLocale); + Configuration config = new Configuration(); + config.locale = currentLocale; + ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); changingConfiguration = false; } - recreateFormatters(); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + } catch (Exception e) { + FileLog.e(e); + changingConfiguration = false; } + recreateFormatters(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); }); } catch (Exception ignore) { @@ -1512,76 +1501,70 @@ public class LocaleController { } loadingRemoteLanguages = true; TLRPC.TL_langpack_getLanguages req = new TLRPC.TL_langpack_getLanguages(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingRemoteLanguages = false; - TLRPC.Vector res = (TLRPC.Vector) response; - HashMap remoteLoaded = new HashMap<>(); - remoteLanguages.clear(); - for (int a = 0; a < res.objects.size(); a++) { - TLRPC.TL_langPackLanguage language = (TLRPC.TL_langPackLanguage) res.objects.get(a); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("loaded lang " + language.name); - } - LocaleInfo localeInfo = new LocaleInfo(); - localeInfo.nameEnglish = language.name; - localeInfo.name = language.native_name; - localeInfo.shortName = language.lang_code.replace('-', '_').toLowerCase(); - localeInfo.pathToFile = "remote"; - - LocaleInfo existing = getLanguageFromDict(localeInfo.getKey()); - if (existing == null) { - languages.add(localeInfo); - languagesDict.put(localeInfo.getKey(), localeInfo); - existing = localeInfo; - } else { - existing.nameEnglish = localeInfo.nameEnglish; - existing.name = localeInfo.name; - existing.pathToFile = localeInfo.pathToFile; - localeInfo = existing; - } - remoteLanguages.add(localeInfo); - remoteLoaded.put(localeInfo.getKey(), existing); - } - for (int a = 0; a < languages.size(); a++) { - LocaleInfo info = languages.get(a); - if (info.isBuiltIn() || !info.isRemote()) { - continue; - } - LocaleInfo existing = remoteLoaded.get(info.getKey()); - if (existing == null) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("remove lang " + info.getKey()); - } - languages.remove(a); - languagesDict.remove(info.getKey()); - a--; - if (info == currentLocaleInfo) { - if (systemDefaultLocale.getLanguage() != null) { - info = getLanguageFromDict(systemDefaultLocale.getLanguage()); - } - if (info == null) { - info = getLanguageFromDict(getLocaleString(systemDefaultLocale)); - } - if (info == null) { - info = getLanguageFromDict("en"); - } - applyLanguage(info, true, false, currentAccount); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); - } - } - } - saveOtherLanguages(); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.suggestedLangpack); - applyLanguage(currentLocaleInfo, true, false, currentAccount); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> { + loadingRemoteLanguages = false; + TLRPC.Vector res = (TLRPC.Vector) response; + HashMap remoteLoaded = new HashMap<>(); + remoteLanguages.clear(); + for (int a = 0; a < res.objects.size(); a++) { + TLRPC.TL_langPackLanguage language = (TLRPC.TL_langPackLanguage) res.objects.get(a); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("loaded lang " + language.name); } - }); - } + LocaleInfo localeInfo = new LocaleInfo(); + localeInfo.nameEnglish = language.name; + localeInfo.name = language.native_name; + localeInfo.shortName = language.lang_code.replace('-', '_').toLowerCase(); + localeInfo.pathToFile = "remote"; + + LocaleInfo existing = getLanguageFromDict(localeInfo.getKey()); + if (existing == null) { + languages.add(localeInfo); + languagesDict.put(localeInfo.getKey(), localeInfo); + existing = localeInfo; + } else { + existing.nameEnglish = localeInfo.nameEnglish; + existing.name = localeInfo.name; + existing.pathToFile = localeInfo.pathToFile; + localeInfo = existing; + } + remoteLanguages.add(localeInfo); + remoteLoaded.put(localeInfo.getKey(), existing); + } + for (int a = 0; a < languages.size(); a++) { + LocaleInfo info = languages.get(a); + if (info.isBuiltIn() || !info.isRemote()) { + continue; + } + LocaleInfo existing = remoteLoaded.get(info.getKey()); + if (existing == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("remove lang " + info.getKey()); + } + languages.remove(a); + languagesDict.remove(info.getKey()); + a--; + if (info == currentLocaleInfo) { + if (systemDefaultLocale.getLanguage() != null) { + info = getLanguageFromDict(systemDefaultLocale.getLanguage()); + } + if (info == null) { + info = getLanguageFromDict(getLocaleString(systemDefaultLocale)); + } + if (info == null) { + info = getLanguageFromDict("en"); + } + applyLanguage(info, true, false, currentAccount); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reloadInterface); + } + } + } + saveOtherLanguages(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.suggestedLangpack); + applyLanguage(currentLocaleInfo, true, false, currentAccount); + }); } }, ConnectionsManager.RequestFlagWithoutLogin); } @@ -1593,17 +1576,9 @@ public class LocaleController { if (localeInfo.version != 0 && !force) { TLRPC.TL_langpack_getDifference req = new TLRPC.TL_langpack_getDifference(); req.from_version = localeInfo.version; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - saveRemoteLocaleStrings((TLRPC.TL_langPackDifference) response, currentAccount); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> saveRemoteLocaleStrings((TLRPC.TL_langPackDifference) response, currentAccount)); } }, ConnectionsManager.RequestFlagWithoutLogin); } else { @@ -1612,23 +1587,22 @@ public class LocaleController { } TLRPC.TL_langpack_getLangPack req = new TLRPC.TL_langpack_getLangPack(); req.lang_code = localeInfo.shortName.replace("_", "-"); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - saveRemoteLocaleStrings((TLRPC.TL_langPackDifference) response, currentAccount); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (TLObject response, TLRPC.TL_error error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> saveRemoteLocaleStrings((TLRPC.TL_langPackDifference) response, currentAccount)); } }, ConnectionsManager.RequestFlagWithoutLogin); } } public String getTranslitString(String src) { + return getTranslitString(src, false); + } + + public String getTranslitString(String src, boolean onlyEnglish) { + if (src == null) { + return null; + } if (translitChars == null) { translitChars = new HashMap<>(520); translitChars.put("ȼ", "c"); @@ -2153,12 +2127,34 @@ public class LocaleController { } StringBuilder dst = new StringBuilder(src.length()); int len = src.length(); + boolean upperCase = false; for (int a = 0; a < len; a++) { String ch = src.substring(a, a + 1); + if (onlyEnglish) { + String lower = ch.toLowerCase(); + upperCase = !ch.equals(lower); + ch = lower; + } String tch = translitChars.get(ch); if (tch != null) { + if (onlyEnglish && upperCase) { + if (tch.length() > 1) { + tch = tch.substring(0, 1).toUpperCase() + tch.substring(1); + } else { + tch = tch.toUpperCase(); + } + } dst.append(tch); } else { + if (onlyEnglish) { + char c = ch.charAt(0); + if (((c < 'a' || c > 'z') || (c < '0' || c > '9')) && c != ' ' && c != '\'' && c != ',' && c != '.' && c != '&' && c != '-' && c != '/') { + return null; + } + if (upperCase) { + ch = ch.toUpperCase(); + } + } dst.append(ch); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java index ba6ce7114..8b8a7e55d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java @@ -140,6 +140,7 @@ public class LocationSharingService extends Service implements NotificationCente builder.setWhen(System.currentTimeMillis()); builder.setSmallIcon(R.drawable.live_loc); builder.setContentIntent(contentIntent); + NotificationsController.checkOtherNotificationsChannel(); builder.setChannelId(NotificationsController.OTHER_NOTIFICATIONS_CHANNEL); builder.setContentTitle(LocaleController.getString("AppName", R.string.AppName)); Intent stopIntent = new Intent(ApplicationLoader.applicationContext, StopLiveLocationReceiver.class); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index a4e684117..74f91605e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -52,10 +52,11 @@ import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.audioinfo.AudioInfo; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.messenger.video.InputSurface; import org.telegram.messenger.video.MP4Builder; import org.telegram.messenger.video.Mp4Movie; @@ -1738,6 +1739,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, FileLog.e(e); return false; } + NotificationCenter.getInstance(messageObject.currentAccount).postNotificationName(NotificationCenter.messagePlayingDidSeek, playingMessageObject.getId(), progress); return true; } @@ -3889,6 +3891,12 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate > 0 ? bitrate : 921600); outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate != 0 ? framerate : 25); outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); + if (Build.VERSION.SDK_INT >= 21) { + outputFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); + if (Build.VERSION.SDK_INT >= 23) { + outputFormat.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel5); + } + } if (Build.VERSION.SDK_INT < 18) { outputFormat.setInteger("stride", resultWidth + 32); outputFormat.setInteger("slice-height", resultHeight); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 50a56821e..08520b048 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -24,6 +24,7 @@ import android.util.Base64; import android.util.SparseArray; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; @@ -1892,7 +1893,7 @@ public class MessageObject { public ArrayList getWebPagePhotos(ArrayList array, ArrayList blocksToSearch) { TLRPC.WebPage webPage = messageOwner.media.webpage; - ArrayList messageObjects = array == null ? new ArrayList() : array; + ArrayList messageObjects = array == null ? new ArrayList<>() : array; if (webPage.cached_page == null) { return messageObjects; } @@ -2220,7 +2221,7 @@ public class MessageObject { } } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { if (!(messageOwner.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) { - if (!update) { + if (!update || photoThumbs == null) { photoThumbs = new ArrayList<>(); photoThumbs.add(messageOwner.media.document.thumb); } else if (photoThumbs != null && !photoThumbs.isEmpty() && messageOwner.media.document.thumb != null) { @@ -2734,6 +2735,9 @@ public class MessageObject { } else if (entity instanceof TLRPC.TL_messageEntityEmail) { spannable.setSpan(new URLSpanReplacement("mailto:" + url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (entity instanceof TLRPC.TL_messageEntityUrl) { + if (Browser.isPassportUrl(entity.url)) { + continue; + } hasUrls = true; if (!url.toLowerCase().startsWith("http") && !url.toLowerCase().startsWith("tg://")) { spannable.setSpan(new URLSpanBrowser("http://" + url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -2746,8 +2750,11 @@ public class MessageObject { if (url.startsWith("+")) { tel = "+" + tel; } - spannable.setSpan(new URLSpanBrowser("tel://" + tel), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spannable.setSpan(new URLSpanBrowser("tel:" + tel), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (entity instanceof TLRPC.TL_messageEntityTextUrl) { + if (Browser.isPassportUrl(entity.url)) { + continue; + } spannable.setSpan(new URLSpanReplacement(entity.url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } @@ -3922,7 +3929,7 @@ public class MessageObject { return messageOwner.fwd_from.from_id; } else if (messageOwner.fwd_from.channel_id != 0) { return -messageOwner.fwd_from.channel_id; - }else { + } else { return -messageOwner.fwd_from.saved_from_peer.chat_id; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index e9baff293..0c781de02 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -29,7 +29,6 @@ import org.telegram.messenger.support.SparseLongArray; import org.telegram.messenger.voip.VoIPService; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; @@ -89,7 +88,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter private SparseIntArray needShortPollChannels = new SparseIntArray(); public boolean loadingBlockedUsers = false; - public ArrayList blockedUsers = new ArrayList<>(); + public SparseIntArray blockedUsers = new SparseIntArray(); private SparseArray> channelViewsToSend = new SparseArray<>(); private long lastViewsCheckTime; @@ -163,12 +162,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public boolean suggestContacts = true; private volatile static long lastThemeCheckTime; - private Runnable themeCheckRunnable = new Runnable() { - @Override - public void run() { - Theme.checkAutoNightThemeConditions(); - } - }; + private Runnable themeCheckRunnable = Theme::checkAutoNightThemeConditions; private volatile static long lastPasswordCheckTime; private Runnable passwordCheckRunnable = new Runnable() { @@ -290,28 +284,25 @@ public class MessagesController implements NotificationCenter.NotificationCenter } }; - private final Comparator updatesComparator = new Comparator() { - @Override - public int compare(TLRPC.Update lhs, TLRPC.Update rhs) { - int ltype = getUpdateType(lhs); - int rtype = getUpdateType(rhs); - if (ltype != rtype) { - return AndroidUtilities.compare(ltype, rtype); - } else if (ltype == 0) { + private final Comparator updatesComparator = (lhs, rhs) -> { + int ltype = getUpdateType(lhs); + int rtype = getUpdateType(rhs); + if (ltype != rtype) { + return AndroidUtilities.compare(ltype, rtype); + } else if (ltype == 0) { + return AndroidUtilities.compare(getUpdatePts(lhs), getUpdatePts(rhs)); + } else if (ltype == 1) { + return AndroidUtilities.compare(getUpdateQts(lhs), getUpdateQts(rhs)); + } else if (ltype == 2) { + int lChannel = getUpdateChannelId(lhs); + int rChannel = getUpdateChannelId(rhs); + if (lChannel == rChannel) { return AndroidUtilities.compare(getUpdatePts(lhs), getUpdatePts(rhs)); - } else if (ltype == 1) { - return AndroidUtilities.compare(getUpdateQts(lhs), getUpdateQts(rhs)); - } else if (ltype == 2) { - int lChannel = getUpdateChannelId(lhs); - int rChannel = getUpdateChannelId(rhs); - if (lChannel == rChannel) { - return AndroidUtilities.compare(getUpdatePts(lhs), getUpdatePts(rhs)); - } else { - return AndroidUtilities.compare(lChannel, rChannel); - } + } else { + return AndroidUtilities.compare(lChannel, rChannel); } - return 0; } + return 0; }; private int currentAccount; @@ -358,17 +349,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter ImageLoader.getInstance(); MessagesStorage.getInstance(currentAccount); LocationController.getInstance(currentAccount); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController messagesController = getInstance(currentAccount); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidUpload); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidFailUpload); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidLoaded); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidFailedLoad); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.messageReceivedByServer); - NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.updateMessageMedia); - } + AndroidUtilities.runOnUIThread(() -> { + MessagesController messagesController = getInstance(currentAccount); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidUpload); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidFailUpload); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.FileDidFailedLoad); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance(currentAccount).addObserver(messagesController, NotificationCenter.updateMessageMedia); }); addSupportUser(); if (currentAccount == 0) { @@ -418,130 +406,127 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void updateConfig(final TLRPC.TL_config config) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - LocaleController.getInstance().loadRemoteLanguages(currentAccount); - maxMegagroupCount = config.megagroup_size_max; - maxGroupCount = config.chat_size_max; - maxEditTime = config.edit_time_limit; - ratingDecay = config.rating_e_decay; - maxRecentGifsCount = config.saved_gifs_limit; - maxRecentStickersCount = config.stickers_recent_limit; - maxFaveStickersCount = config.stickers_faved_limit; - revokeTimeLimit = config.revoke_time_limit; - revokeTimePmLimit = config.revoke_pm_time_limit; - canRevokePmInbox = config.revoke_pm_inbox; - linkPrefix = config.me_url_prefix; - if (linkPrefix.endsWith("/")) { - linkPrefix = linkPrefix.substring(0, linkPrefix.length() - 1); - } - if (linkPrefix.startsWith("https://")) { - linkPrefix = linkPrefix.substring(8); - } else if (linkPrefix.startsWith("http://")) { - linkPrefix = linkPrefix.substring(7); - } - callReceiveTimeout = config.call_receive_timeout_ms; - callRingTimeout = config.call_ring_timeout_ms; - callConnectTimeout = config.call_connect_timeout_ms; - callPacketTimeout = config.call_packet_timeout_ms; - maxPinnedDialogsCount = config.pinned_dialogs_count_max; - maxMessageLength = config.message_length_max; - maxCaptionLength = config.caption_length_max; - defaultP2pContacts = config.default_p2p_contacts; - preloadFeaturedStickers = config.preload_featured_stickers; - if (config.venue_search_username != null) { - venueSearchBot = config.venue_search_username; - } - if (config.gif_search_username != null) { - gifSearchBot = config.gif_search_username; - } - if (imageSearchBot != null) { - imageSearchBot = config.img_search_username; - } - blockedCountry = config.blocked_mode; - dcDomainName = config.dc_txt_domain_name; - webFileDatacenterId = config.webfile_dc_id; + AndroidUtilities.runOnUIThread(() -> { + LocaleController.getInstance().loadRemoteLanguages(currentAccount); + maxMegagroupCount = config.megagroup_size_max; + maxGroupCount = config.chat_size_max; + maxEditTime = config.edit_time_limit; + ratingDecay = config.rating_e_decay; + maxRecentGifsCount = config.saved_gifs_limit; + maxRecentStickersCount = config.stickers_recent_limit; + maxFaveStickersCount = config.stickers_faved_limit; + revokeTimeLimit = config.revoke_time_limit; + revokeTimePmLimit = config.revoke_pm_time_limit; + canRevokePmInbox = config.revoke_pm_inbox; + linkPrefix = config.me_url_prefix; + if (linkPrefix.endsWith("/")) { + linkPrefix = linkPrefix.substring(0, linkPrefix.length() - 1); + } + if (linkPrefix.startsWith("https://")) { + linkPrefix = linkPrefix.substring(8); + } else if (linkPrefix.startsWith("http://")) { + linkPrefix = linkPrefix.substring(7); + } + callReceiveTimeout = config.call_receive_timeout_ms; + callRingTimeout = config.call_ring_timeout_ms; + callConnectTimeout = config.call_connect_timeout_ms; + callPacketTimeout = config.call_packet_timeout_ms; + maxPinnedDialogsCount = config.pinned_dialogs_count_max; + maxMessageLength = config.message_length_max; + maxCaptionLength = config.caption_length_max; + defaultP2pContacts = config.default_p2p_contacts; + preloadFeaturedStickers = config.preload_featured_stickers; + if (config.venue_search_username != null) { + venueSearchBot = config.venue_search_username; + } + if (config.gif_search_username != null) { + gifSearchBot = config.gif_search_username; + } + if (imageSearchBot != null) { + imageSearchBot = config.img_search_username; + } + blockedCountry = config.blocked_mode; + dcDomainName = config.dc_txt_domain_name; + webFileDatacenterId = config.webfile_dc_id; - if (config.static_maps_provider == null) { - config.static_maps_provider = "google"; - } + if (config.static_maps_provider == null) { + config.static_maps_provider = "google"; + } - mapKey = null; - mapProvider = 0; - availableMapProviders = 0; - String[] providers = config.static_maps_provider.split(","); - for (int a = 0; a < providers.length; a++) { - String[] mapArgs = providers[a].split("\\+"); - if (mapArgs.length > 0) { - String[] typeAndKey = mapArgs[0].split(":"); - if (typeAndKey.length > 0) { - if ("yandex".equals(typeAndKey[0])) { - if (a == 0) { - if (mapArgs.length > 1) { - mapProvider = 3; - } else { - mapProvider = 1; - } + mapKey = null; + mapProvider = 0; + availableMapProviders = 0; + String[] providers = config.static_maps_provider.split(","); + for (int a = 0; a < providers.length; a++) { + String[] mapArgs = providers[a].split("\\+"); + if (mapArgs.length > 0) { + String[] typeAndKey = mapArgs[0].split(":"); + if (typeAndKey.length > 0) { + if ("yandex".equals(typeAndKey[0])) { + if (a == 0) { + if (mapArgs.length > 1) { + mapProvider = 3; + } else { + mapProvider = 1; } - availableMapProviders |= 4; - } else if ("google".equals(typeAndKey[0])) { - if (a == 0) { - if (mapArgs.length > 1) { - mapProvider = 4; - } - } - availableMapProviders |= 1; - } else if ("telegram".equals(typeAndKey[0])) { - if (a == 0) { - mapProvider = 2; - } - availableMapProviders |= 2; } - if (typeAndKey.length > 1) { - mapKey = typeAndKey[1]; + availableMapProviders |= 4; + } else if ("google".equals(typeAndKey[0])) { + if (a == 0) { + if (mapArgs.length > 1) { + mapProvider = 4; + } } + availableMapProviders |= 1; + } else if ("telegram".equals(typeAndKey[0])) { + if (a == 0) { + mapProvider = 2; + } + availableMapProviders |= 2; + } + if (typeAndKey.length > 1) { + mapKey = typeAndKey[1]; } } } - - SharedPreferences.Editor editor = mainPreferences.edit(); - editor.putInt("maxGroupCount", maxGroupCount); - editor.putInt("maxMegagroupCount", maxMegagroupCount); - editor.putInt("maxEditTime", maxEditTime); - editor.putInt("ratingDecay", ratingDecay); - editor.putInt("maxRecentGifsCount", maxRecentGifsCount); - editor.putInt("maxRecentStickersCount", maxRecentStickersCount); - editor.putInt("maxFaveStickersCount", maxFaveStickersCount); - editor.putInt("callReceiveTimeout", callReceiveTimeout); - editor.putInt("callRingTimeout", callRingTimeout); - editor.putInt("callConnectTimeout", callConnectTimeout); - editor.putInt("callPacketTimeout", callPacketTimeout); - editor.putString("linkPrefix", linkPrefix); - editor.putInt("maxPinnedDialogsCount", maxPinnedDialogsCount); - editor.putInt("maxMessageLength", maxMessageLength); - editor.putInt("maxCaptionLength", maxCaptionLength); - editor.putBoolean("defaultP2pContacts", defaultP2pContacts); - editor.putBoolean("preloadFeaturedStickers", preloadFeaturedStickers); - editor.putInt("revokeTimeLimit", revokeTimeLimit); - editor.putInt("revokeTimePmLimit", revokeTimePmLimit); - editor.putInt("mapProvider", mapProvider); - if (mapKey != null) { - editor.putString("pk", mapKey); - } else { - editor.remove("pk"); - } - editor.putBoolean("canRevokePmInbox", canRevokePmInbox); - editor.putBoolean("blockedCountry", blockedCountry); - editor.putString("venueSearchBot", venueSearchBot); - editor.putString("gifSearchBot", gifSearchBot); - editor.putString("imageSearchBot", imageSearchBot); - editor.putString("dcDomainName", dcDomainName); - editor.putInt("webFileDatacenterId", webFileDatacenterId); - editor.commit(); - - LocaleController.getInstance().checkUpdateForCurrentRemoteLocale(currentAccount, config.lang_pack_version); } + + SharedPreferences.Editor editor = mainPreferences.edit(); + editor.putInt("maxGroupCount", maxGroupCount); + editor.putInt("maxMegagroupCount", maxMegagroupCount); + editor.putInt("maxEditTime", maxEditTime); + editor.putInt("ratingDecay", ratingDecay); + editor.putInt("maxRecentGifsCount", maxRecentGifsCount); + editor.putInt("maxRecentStickersCount", maxRecentStickersCount); + editor.putInt("maxFaveStickersCount", maxFaveStickersCount); + editor.putInt("callReceiveTimeout", callReceiveTimeout); + editor.putInt("callRingTimeout", callRingTimeout); + editor.putInt("callConnectTimeout", callConnectTimeout); + editor.putInt("callPacketTimeout", callPacketTimeout); + editor.putString("linkPrefix", linkPrefix); + editor.putInt("maxPinnedDialogsCount", maxPinnedDialogsCount); + editor.putInt("maxMessageLength", maxMessageLength); + editor.putInt("maxCaptionLength", maxCaptionLength); + editor.putBoolean("defaultP2pContacts", defaultP2pContacts); + editor.putBoolean("preloadFeaturedStickers", preloadFeaturedStickers); + editor.putInt("revokeTimeLimit", revokeTimeLimit); + editor.putInt("revokeTimePmLimit", revokeTimePmLimit); + editor.putInt("mapProvider", mapProvider); + if (mapKey != null) { + editor.putString("pk", mapKey); + } else { + editor.remove("pk"); + } + editor.putBoolean("canRevokePmInbox", canRevokePmInbox); + editor.putBoolean("blockedCountry", blockedCountry); + editor.putString("venueSearchBot", venueSearchBot); + editor.putString("gifSearchBot", gifSearchBot); + editor.putString("imageSearchBot", imageSearchBot); + editor.putString("dcDomainName", dcDomainName); + editor.putInt("webFileDatacenterId", webFileDatacenterId); + editor.commit(); + + LocaleController.getInstance().checkUpdateForCurrentRemoteLocale(currentAccount, config.lang_pack_version); }); } @@ -651,46 +636,40 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (uploadingAvatar != null && uploadingAvatar.equals(location)) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); req.file = file; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.User user = getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user == null) { - user = UserConfig.getInstance(currentAccount).getCurrentUser(); - putUser(user, true); - } else { - UserConfig.getInstance(currentAccount).setCurrentUser(user); - } - if (user == null) { - return; - } - TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; - ArrayList sizes = photo.photo.sizes; - TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100); - TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000); - user.photo = new TLRPC.TL_userProfilePhoto(); - user.photo.photo_id = photo.photo.id; - if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - if (bigSize != null) { - user.photo.photo_big = bigSize.location; - } else if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); - ArrayList users = new ArrayList<>(); - users.add(user); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR); - UserConfig.getInstance(currentAccount).saveConfig(true); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.User user = getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user == null) { + user = UserConfig.getInstance(currentAccount).getCurrentUser(); + putUser(user, true); + } else { + UserConfig.getInstance(currentAccount).setCurrentUser(user); } + if (user == null) { + return; + } + TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; + ArrayList sizes = photo.photo.sizes; + TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100); + TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000); + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photo.photo.id; + if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + if (bigSize != null) { + user.photo.photo_big = bigSize.location; + } else if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR); + UserConfig.getInstance(currentAccount).saveConfig(true); + }); } }); } @@ -778,23 +757,20 @@ public class MessagesController implements NotificationCenter.NotificationCenter loadingPeerSettings.clear(); lastPrintingStringCount = 0; nextDialogsCacheOffset = 0; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - readTasks.clear(); - readTasksMap.clear(); - updatesQueueSeq.clear(); - updatesQueuePts.clear(); - updatesQueueQts.clear(); - gettingUnknownChannels.clear(); - updatesStartWaitTimeSeq = 0; - updatesStartWaitTimePts = 0; - updatesStartWaitTimeQts = 0; - createdDialogIds.clear(); - gettingDifference = false; - resetDialogsPinned = null; - resetDialogsAll = null; - } + Utilities.stageQueue.postRunnable(() -> { + readTasks.clear(); + readTasksMap.clear(); + updatesQueueSeq.clear(); + updatesQueuePts.clear(); + updatesQueueQts.clear(); + gettingUnknownChannels.clear(); + updatesStartWaitTimeSeq = 0; + updatesStartWaitTimePts = 0; + updatesStartWaitTimeQts = 0; + createdDialogIds.clear(); + gettingDifference = false; + resetDialogsPinned = null; + resetDialogsAll = null; }); createdDialogMainThreadIds.clear(); visibleDialogMainThreadIds.clear(); @@ -833,17 +809,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter statusRequest = 0; statusSettingState = 0; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); - updatesQueueChannels.clear(); - updatesStartWaitTimeChannels.clear(); - gettingDifferenceChannels.clear(); - channelsPts.clear(); - shortPollChannels.clear(); - needShortPollChannels.clear(); - } + Utilities.stageQueue.postRunnable(() -> { + ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); + updatesQueueChannels.clear(); + updatesStartWaitTimeChannels.clear(); + gettingDifferenceChannels.clear(); + channelsPts.clear(); + shortPollChannels.clear(); + needShortPollChannels.clear(); }); if (currentDeleteTaskRunnable != null) { @@ -927,17 +900,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { createdDialogMainThreadIds.remove(dialog_id); } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (set) { - if (createdDialogIds.contains(dialog_id)) { - return; - } - createdDialogIds.add(dialog_id); - } else { - createdDialogIds.remove(dialog_id); + Utilities.stageQueue.postRunnable(() -> { + if (set) { + if (createdDialogIds.contains(dialog_id)) { + return; } + createdDialogIds.add(dialog_id); + } else { + createdDialogIds.remove(dialog_id); } }); } @@ -1033,12 +1003,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } if (updateStatus) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS)); } } @@ -1092,12 +1057,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter int oldFlags = oldChat.banned_rights != null ? oldChat.banned_rights.flags : 0; int newFlags = chat.banned_rights != null ? chat.banned_rights.flags : 0; if (oldFlags != newFlags) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.channelRightsUpdated, chat); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.channelRightsUpdated, chat)); } } chats.put(chat.id, chat); @@ -1212,71 +1172,68 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (req.peers.isEmpty()) { return; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; - ArrayList arrayList = new ArrayList<>(); - for (int a = 0; a < res.dialogs.size(); a++) { - TLRPC.TL_dialog dialog = res.dialogs.get(a); - if (dialog.read_inbox_max_id == 0) { - dialog.read_inbox_max_id = 1; - } - if (dialog.read_outbox_max_id == 0) { - dialog.read_outbox_max_id = 1; - } - if (dialog.id == 0 && dialog.peer != null) { - if (dialog.peer.user_id != 0) { - dialog.id = dialog.peer.user_id; - } else if (dialog.peer.chat_id != 0) { - dialog.id = -dialog.peer.chat_id; - } else if (dialog.peer.channel_id != 0) { - dialog.id = -dialog.peer.channel_id; - } - } - - Integer value = dialogs_read_inbox_max.get(dialog.id); - if (value == null) { - value = 0; - } - dialogs_read_inbox_max.put(dialog.id, Math.max(dialog.read_inbox_max_id, value)); - if (value == 0) { - if (dialog.peer.channel_id != 0) { - TLRPC.TL_updateReadChannelInbox update = new TLRPC.TL_updateReadChannelInbox(); - update.channel_id = dialog.peer.channel_id; - update.max_id = dialog.read_inbox_max_id; - arrayList.add(update); - } else { - TLRPC.TL_updateReadHistoryInbox update = new TLRPC.TL_updateReadHistoryInbox(); - update.peer = dialog.peer; - update.max_id = dialog.read_inbox_max_id; - arrayList.add(update); - } - } - - value = dialogs_read_outbox_max.get(dialog.id); - if (value == null) { - value = 0; - } - dialogs_read_outbox_max.put(dialog.id, Math.max(dialog.read_outbox_max_id, value)); - if (value == 0) { - if (dialog.peer.channel_id != 0) { - TLRPC.TL_updateReadChannelOutbox update = new TLRPC.TL_updateReadChannelOutbox(); - update.channel_id = dialog.peer.channel_id; - update.max_id = dialog.read_outbox_max_id; - arrayList.add(update); - } else { - TLRPC.TL_updateReadHistoryOutbox update = new TLRPC.TL_updateReadHistoryOutbox(); - update.peer = dialog.peer; - update.max_id = dialog.read_outbox_max_id; - arrayList.add(update); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; + ArrayList arrayList = new ArrayList<>(); + for (int a = 0; a < res.dialogs.size(); a++) { + TLRPC.TL_dialog dialog = res.dialogs.get(a); + if (dialog.read_inbox_max_id == 0) { + dialog.read_inbox_max_id = 1; + } + if (dialog.read_outbox_max_id == 0) { + dialog.read_outbox_max_id = 1; + } + if (dialog.id == 0 && dialog.peer != null) { + if (dialog.peer.user_id != 0) { + dialog.id = dialog.peer.user_id; + } else if (dialog.peer.chat_id != 0) { + dialog.id = -dialog.peer.chat_id; + } else if (dialog.peer.channel_id != 0) { + dialog.id = -dialog.peer.channel_id; } } - if (!arrayList.isEmpty()) { - processUpdateArray(arrayList, null, null, false); + + Integer value = dialogs_read_inbox_max.get(dialog.id); + if (value == null) { + value = 0; } + dialogs_read_inbox_max.put(dialog.id, Math.max(dialog.read_inbox_max_id, value)); + if (value == 0) { + if (dialog.peer.channel_id != 0) { + TLRPC.TL_updateReadChannelInbox update = new TLRPC.TL_updateReadChannelInbox(); + update.channel_id = dialog.peer.channel_id; + update.max_id = dialog.read_inbox_max_id; + arrayList.add(update); + } else { + TLRPC.TL_updateReadHistoryInbox update = new TLRPC.TL_updateReadHistoryInbox(); + update.peer = dialog.peer; + update.max_id = dialog.read_inbox_max_id; + arrayList.add(update); + } + } + + value = dialogs_read_outbox_max.get(dialog.id); + if (value == null) { + value = 0; + } + dialogs_read_outbox_max.put(dialog.id, Math.max(dialog.read_outbox_max_id, value)); + if (value == 0) { + if (dialog.peer.channel_id != 0) { + TLRPC.TL_updateReadChannelOutbox update = new TLRPC.TL_updateReadChannelOutbox(); + update.channel_id = dialog.peer.channel_id; + update.max_id = dialog.read_outbox_max_id; + arrayList.add(update); + } else { + TLRPC.TL_updateReadHistoryOutbox update = new TLRPC.TL_updateReadHistoryOutbox(); + update.peer = dialog.peer; + update.max_id = dialog.read_outbox_max_id; + arrayList.add(update); + } + } + } + if (!arrayList.isEmpty()) { + processUpdateArray(arrayList, null, null, false); } } }); @@ -1307,17 +1264,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.channel = getInputChannel(chatId); req.limit = 100; req.filter = new TLRPC.TL_channelParticipantsAdmins(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_channels_channelParticipants) { - TLRPC.TL_channels_channelParticipants participants = (TLRPC.TL_channels_channelParticipants) response; - final ArrayList array = new ArrayList<>(participants.participants.size()); - for (int a = 0; a < participants.participants.size(); a++) { - array.add(participants.participants.get(a).user_id); - } - processLoadedChannelAdmins(array, chatId, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_channels_channelParticipants) { + TLRPC.TL_channels_channelParticipants participants = (TLRPC.TL_channels_channelParticipants) response; + final ArrayList array1 = new ArrayList<>(participants.participants.size()); + for (int a = 0; a < participants.participants.size(); a++) { + array1.add(participants.participants.get(a).user_id); } + processLoadedChannelAdmins(array1, chatId, false); } }); } @@ -1328,14 +1282,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!cache) { MessagesStorage.getInstance(currentAccount).putChannelAdmins(chatId, array); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingChannelAdmins.delete(chatId); - channelAdmins.put(chatId, array); - if (cache) { - loadChannelAdmins(chatId, false); - } + AndroidUtilities.runOnUIThread(() -> { + loadingChannelAdmins.delete(chatId); + channelAdmins.put(chatId, array); + if (cache) { + loadChannelAdmins(chatId, false); } }); } @@ -1364,74 +1315,65 @@ public class MessagesController implements NotificationCenter.NotificationCenter reloadDialogsReadValue(null, dialog_id); } } - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - final TLRPC.TL_messages_chatFull res = (TLRPC.TL_messages_chatFull) response; - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - MessagesStorage.getInstance(currentAccount).updateChatInfo(res.full_chat, false); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (error == null) { + final TLRPC.TL_messages_chatFull res = (TLRPC.TL_messages_chatFull) response; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + MessagesStorage.getInstance(currentAccount).updateChatInfo(res.full_chat, false); - if (ChatObject.isChannel(chat)) { - Integer value = dialogs_read_inbox_max.get(dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); - } - - dialogs_read_inbox_max.put(dialog_id, Math.max(res.full_chat.read_inbox_max_id, value)); - if (value == 0) { - ArrayList arrayList = new ArrayList<>(); - TLRPC.TL_updateReadChannelInbox update = new TLRPC.TL_updateReadChannelInbox(); - update.channel_id = chat_id; - update.max_id = res.full_chat.read_inbox_max_id; - arrayList.add(update); - processUpdateArray(arrayList, null, null, false); - } - - value = dialogs_read_outbox_max.get(dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); - } - dialogs_read_outbox_max.put(dialog_id, Math.max(res.full_chat.read_outbox_max_id, value)); - if (value == 0) { - ArrayList arrayList = new ArrayList<>(); - TLRPC.TL_updateReadChannelOutbox update = new TLRPC.TL_updateReadChannelOutbox(); - update.channel_id = chat_id; - update.max_id = res.full_chat.read_outbox_max_id; - arrayList.add(update); - processUpdateArray(arrayList, null, null, false); - } + if (ChatObject.isChannel(chat)) { + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - applyDialogNotificationsSettings(-chat_id, res.full_chat.notify_settings); - for (int a = 0; a < res.full_chat.bot_info.size(); a++) { - TLRPC.BotInfo botInfo = res.full_chat.bot_info.get(a); - DataQuery.getInstance(currentAccount).putBotInfo(botInfo); - } - exportedChats.put(chat_id, res.full_chat.exported_invite); - loadingFullChats.remove((Integer) chat_id); - loadedFullChats.add(chat_id); + dialogs_read_inbox_max.put(dialog_id, Math.max(res.full_chat.read_inbox_max_id, value)); + if (value == 0) { + ArrayList arrayList = new ArrayList<>(); + TLRPC.TL_updateReadChannelInbox update = new TLRPC.TL_updateReadChannelInbox(); + update.channel_id = chat_id; + update.max_id = res.full_chat.read_inbox_max_id; + arrayList.add(update); + processUpdateArray(arrayList, null, null, false); + } - putUsers(res.users, false); - putChats(res.chats, false); - if (res.full_chat.stickerset != null) { - DataQuery.getInstance(currentAccount).getGroupStickerSetById(res.full_chat.stickerset); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, res.full_chat, classGuid, false, null); - } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkChannelError(error.text, chat_id); - loadingFullChats.remove((Integer) chat_id); - } - }); + value = dialogs_read_outbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); + } + dialogs_read_outbox_max.put(dialog_id, Math.max(res.full_chat.read_outbox_max_id, value)); + if (value == 0) { + ArrayList arrayList = new ArrayList<>(); + TLRPC.TL_updateReadChannelOutbox update = new TLRPC.TL_updateReadChannelOutbox(); + update.channel_id = chat_id; + update.max_id = res.full_chat.read_outbox_max_id; + arrayList.add(update); + processUpdateArray(arrayList, null, null, false); + } } + + AndroidUtilities.runOnUIThread(() -> { + applyDialogNotificationsSettings(-chat_id, res.full_chat.notify_settings); + for (int a = 0; a < res.full_chat.bot_info.size(); a++) { + TLRPC.BotInfo botInfo = res.full_chat.bot_info.get(a); + DataQuery.getInstance(currentAccount).putBotInfo(botInfo); + } + exportedChats.put(chat_id, res.full_chat.exported_invite); + loadingFullChats.remove((Integer) chat_id); + loadedFullChats.add(chat_id); + + putUsers(res.users, false); + putChats(res.chats, false); + if (res.full_chat.stickerset != null) { + DataQuery.getInstance(currentAccount).getGroupStickerSetById(res.full_chat.stickerset); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, res.full_chat, classGuid, false, null); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + checkChannelError(error.text, chat_id); + loadingFullChats.remove((Integer) chat_id); + }); } }); if (classGuid != 0) { @@ -1450,43 +1392,50 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (dialogs_read_inbox_max.get(dialog_id) == null || dialogs_read_outbox_max.get(dialog_id) == null) { reloadDialogsReadValue(null, dialog_id); } - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (error == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.TL_userFull userFull = (TLRPC.TL_userFull) response; - applyDialogNotificationsSettings(user.id, userFull.notify_settings); - if (userFull.bot_info instanceof TLRPC.TL_botInfo) { - DataQuery.getInstance(currentAccount).putBotInfo(userFull.bot_info); - } - fullUsers.put(user.id, userFull); - loadingFullUsers.remove((Integer) user.id); - loadedFullUsers.add(user.id); - String names = user.first_name + user.last_name + user.username; - ArrayList users = new ArrayList<>(); - users.add(userFull.user); - putUsers(users, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); - if (names != null && !names.equals(userFull.user.first_name + userFull.user.last_name + userFull.user.username)) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_NAME); - } - if (userFull.bot_info instanceof TLRPC.TL_botInfo) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.botInfoDidLoaded, userFull.bot_info, classGuid); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoaded, user.id, userFull); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_userFull userFull = (TLRPC.TL_userFull) response; + applyDialogNotificationsSettings(user.id, userFull.notify_settings); + if (userFull.bot_info instanceof TLRPC.TL_botInfo) { + DataQuery.getInstance(currentAccount).putBotInfo(userFull.bot_info); + } + int index = blockedUsers.indexOfKey(user.id); + if (userFull.blocked) { + if (index < 0) { + SparseIntArray ids = new SparseIntArray(); + ids.put(user.id, 1); + MessagesStorage.getInstance(currentAccount).putBlockedUsers(ids, false); + + blockedUsers.put(user.id, 1); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingFullUsers.remove((Integer) user.id); + } else { + if (index >= 0) { + MessagesStorage.getInstance(currentAccount).deleteBlockedUser(user.id); + + blockedUsers.removeAt(index); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); } - }); - } + } + fullUsers.put(user.id, userFull); + loadingFullUsers.remove((Integer) user.id); + loadedFullUsers.add(user.id); + String names = user.first_name + user.last_name + user.username; + ArrayList users = new ArrayList<>(); + users.add(userFull.user); + putUsers(users, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); + if (names != null && !names.equals(userFull.user.first_name + userFull.user.last_name + userFull.user.username)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_NAME); + } + if (userFull.bot_info instanceof TLRPC.TL_botInfo) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.botInfoDidLoaded, userFull.bot_info, classGuid); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoaded, user.id, userFull); + }); + } else { + AndroidUtilities.runOnUIThread(() -> loadingFullUsers.remove((Integer) user.id)); } }); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); @@ -1525,81 +1474,75 @@ public class MessagesController implements NotificationCenter.NotificationCenter reloadingMessages.put(dialog_id, arrayList); } arrayList.addAll(result); - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; - final SparseArray usersLocal = new SparseArray<>(); - for (int a = 0; a < messagesRes.users.size(); a++) { - TLRPC.User u = messagesRes.users.get(a); - usersLocal.put(u.id, u); - } - final SparseArray chatsLocal = new SparseArray<>(); - for (int a = 0; a < messagesRes.chats.size(); a++) { - TLRPC.Chat c = messagesRes.chats.get(a); - chatsLocal.put(c.id, c); - } + final SparseArray usersLocal = new SparseArray<>(); + for (int a = 0; a < messagesRes.users.size(); a++) { + TLRPC.User u = messagesRes.users.get(a); + usersLocal.put(u.id, u); + } + final SparseArray chatsLocal = new SparseArray<>(); + for (int a = 0; a < messagesRes.chats.size(); a++) { + TLRPC.Chat c = messagesRes.chats.get(a); + chatsLocal.put(c.id, c); + } - Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); - if (inboxValue == null) { - inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); - dialogs_read_inbox_max.put(dialog_id, inboxValue); - } + Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); + if (inboxValue == null) { + inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); + dialogs_read_inbox_max.put(dialog_id, inboxValue); + } - Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); - if (outboxValue == null) { - outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); - dialogs_read_outbox_max.put(dialog_id, outboxValue); - } + Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); + if (outboxValue == null) { + outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); + dialogs_read_outbox_max.put(dialog_id, outboxValue); + } - final ArrayList objects = new ArrayList<>(); - for (int a = 0; a < messagesRes.messages.size(); a++) { - TLRPC.Message message = messagesRes.messages.get(a); - if (chat != null && chat.megagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + final ArrayList objects = new ArrayList<>(); + for (int a = 0; a < messagesRes.messages.size(); a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (chat != null && chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + message.dialog_id = dialog_id; + message.unread = (message.out ? outboxValue : inboxValue) < message.id; + objects.add(new MessageObject(currentAccount, message, usersLocal, chatsLocal, true)); + } + + ImageLoader.saveMessagesThumbs(messagesRes.messages); + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, -1, 0, false); + + AndroidUtilities.runOnUIThread(() -> { + ArrayList arrayList1 = reloadingMessages.get(dialog_id); + if (arrayList1 != null) { + arrayList1.removeAll(result); + if (arrayList1.isEmpty()) { + reloadingMessages.remove(dialog_id); } - message.dialog_id = dialog_id; - message.unread = (message.out ? outboxValue : inboxValue) < message.id; - objects.add(new MessageObject(currentAccount, message, usersLocal, chatsLocal, true)); } - - ImageLoader.saveMessagesThumbs(messagesRes.messages); - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, -1, 0, false); - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - ArrayList arrayList = reloadingMessages.get(dialog_id); - if (arrayList != null) { - arrayList.removeAll(result); - if (arrayList.isEmpty()) { - reloadingMessages.remove(dialog_id); - } - } - MessageObject dialogObj = dialogMessage.get(dialog_id); - if (dialogObj != null) { - for (int a = 0; a < objects.size(); a++) { - MessageObject obj = objects.get(a); - if (dialogObj != null && dialogObj.getId() == obj.getId()) { - dialogMessage.put(dialog_id, obj); - if (obj.messageOwner.to_id.channel_id == 0) { - MessageObject obj2 = dialogMessagesByIds.get(obj.getId()); - dialogMessagesByIds.remove(obj.getId()); - if (obj2 != null) { - dialogMessagesByIds.put(obj2.getId(), obj2); - } - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - break; + MessageObject dialogObj = dialogMessage.get(dialog_id); + if (dialogObj != null) { + for (int a = 0; a < objects.size(); a++) { + MessageObject obj = objects.get(a); + if (dialogObj != null && dialogObj.getId() == obj.getId()) { + dialogMessage.put(dialog_id, obj); + if (obj.messageOwner.to_id.channel_id == 0) { + MessageObject obj2 = dialogMessagesByIds.get(obj.getId()); + dialogMessagesByIds.remove(obj.getId()); + if (obj2 != null) { + dialogMessagesByIds.put(obj2.getId(), obj2); } } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + break; } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, objects); } - }); - } + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, objects); + }); } }); } @@ -1618,11 +1561,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (currentChat != null) { req.peer = getInputPeer(-currentChat.id); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -1642,11 +1582,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer = new TLRPC.TL_inputEncryptedChat(); req.peer.chat_id = currentEncryptedChat.id; req.peer.access_hash = currentEncryptedChat.access_hash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }, ConnectionsManager.RequestFlagFailOnServerErrors); } else { TLRPC.TL_messages_reportSpam req = new TLRPC.TL_messages_reportSpam(); @@ -1655,11 +1592,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (currentUser != null) { req.peer = getInputPeer(currentUser.id); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }, ConnectionsManager.RequestFlagFailOnServerErrors); } } @@ -1695,21 +1629,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (currentChat != null) { req.peer = getInputPeer(-currentChat.id); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingPeerSettings.remove(dialogId); - SharedPreferences.Editor editor = notificationsPreferences.edit(); - editor.remove("spam_" + dialogId); - editor.putInt("spam3_" + dialogId, 1); - editor.commit(); - } - }); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + loadingPeerSettings.remove(dialogId); + SharedPreferences.Editor editor = notificationsPreferences.edit(); + editor.remove("spam_" + dialogId); + editor.putInt("spam3_" + dialogId, 1); + editor.commit(); + })); return; } TLRPC.TL_messages_getPeerSettings req = new TLRPC.TL_messages_getPeerSettings(); @@ -1718,35 +1644,27 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (currentChat != null) { req.peer = getInputPeer(-currentChat.id); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingPeerSettings.remove(dialogId); - if (response != null) { - TLRPC.TL_peerSettings res = (TLRPC.TL_peerSettings) response; - SharedPreferences.Editor editor = notificationsPreferences.edit(); - if (!res.report_spam) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("don't show spam button for " + dialogId); - } - editor.putInt("spam3_" + dialogId, 1); - editor.commit(); - } else { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("show spam button for " + dialogId); - } - editor.putInt("spam3_" + dialogId, 2); - editor.commit(); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.peerSettingsDidLoaded, dialogId); - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + loadingPeerSettings.remove(dialogId); + if (response != null) { + TLRPC.TL_peerSettings res = (TLRPC.TL_peerSettings) response; + SharedPreferences.Editor editor = notificationsPreferences.edit(); + if (!res.report_spam) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("don't show spam button for " + dialogId); } - }); + editor.putInt("spam3_" + dialogId, 1); + editor.commit(); + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("show spam button for " + dialogId); + } + editor.putInt("spam3_" + dialogId, 2); + editor.commit(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.peerSettingsDidLoaded, dialogId); + } } - }); + })); } protected void processNewChannelDifferenceParams(int pts, int pts_count, int channelId) { @@ -1850,29 +1768,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void didAddedNewTask(final int minDate, final SparseArray> mids) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (currentDeletingTaskMids == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) { - getNewDeleteTask(null, 0); - } - } - }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didCreatedNewDeleteTask, mids); + Utilities.stageQueue.postRunnable(() -> { + if (currentDeletingTaskMids == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) { + getNewDeleteTask(null, 0); } }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didCreatedNewDeleteTask, mids)); } public void getNewDeleteTask(final ArrayList oldTask, final int channelId) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - gettingNewDeleteTask = true; - MessagesStorage.getInstance(currentAccount).getNewTask(oldTask, channelId); - } + Utilities.stageQueue.postRunnable(() -> { + gettingNewDeleteTask = true; + MessagesStorage.getInstance(currentAccount).getNewTask(oldTask, channelId); }); } @@ -1886,23 +1793,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter } currentDeleteTaskRunnable = null; final ArrayList mids = new ArrayList<>(currentDeletingTaskMids); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!mids.isEmpty() && mids.get(0) > 0) { - MessagesStorage.getInstance(currentAccount).emptyMessagesMedia(mids); - } else { - deleteMessages(mids, null, null, 0, false); - } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - getNewDeleteTask(mids, currentDeletingTaskChannelId); - currentDeletingTaskTime = 0; - currentDeletingTaskMids = null; - } - }); + AndroidUtilities.runOnUIThread(() -> { + if (!mids.isEmpty() && mids.get(0) > 0) { + MessagesStorage.getInstance(currentAccount).emptyMessagesMedia(mids); + } else { + deleteMessages(mids, null, null, 0, false); } + Utilities.stageQueue.postRunnable(() -> { + getNewDeleteTask(mids, currentDeletingTaskChannelId); + currentDeletingTaskTime = 0; + currentDeletingTaskMids = null; + }); }); return true; } @@ -1910,33 +1811,25 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void processLoadedDeleteTask(final int taskTime, final ArrayList messages, final int channelId) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - gettingNewDeleteTask = false; - if (messages != null) { - currentDeletingTaskTime = taskTime; - currentDeletingTaskMids = messages; + Utilities.stageQueue.postRunnable(() -> { + gettingNewDeleteTask = false; + if (messages != null) { + currentDeletingTaskTime = taskTime; + currentDeletingTaskMids = messages; - if (currentDeleteTaskRunnable != null) { - Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); - currentDeleteTaskRunnable = null; - } - - if (!checkDeletingTask(false)) { - currentDeleteTaskRunnable = new Runnable() { - @Override - public void run() { - checkDeletingTask(true); - } - }; - int currentServerTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - Utilities.stageQueue.postRunnable(currentDeleteTaskRunnable, (long) Math.abs(currentServerTime - currentDeletingTaskTime) * 1000); - } - } else { - currentDeletingTaskTime = 0; - currentDeletingTaskMids = null; + if (currentDeleteTaskRunnable != null) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + currentDeleteTaskRunnable = null; } + + if (!checkDeletingTask(false)) { + currentDeleteTaskRunnable = () -> checkDeletingTask(true); + int currentServerTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + Utilities.stageQueue.postRunnable(currentDeleteTaskRunnable, (long) Math.abs(currentServerTime - currentDeletingTaskTime) * 1000); + } + } else { + currentDeletingTaskTime = 0; + currentDeletingTaskMids = null; } }); } @@ -1955,13 +1848,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.offset = 0; req.max_id = (int) max_id; req.user_id = getInputUser(user); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.photos_Photos res = (TLRPC.photos_Photos) response; - processLoadedUserPhotos(res, did, count, max_id, false, classGuid); - } + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.photos_Photos res = (TLRPC.photos_Photos) response; + processLoadedUserPhotos(res, did, count, max_id, false, classGuid); } }); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); @@ -1972,23 +1862,20 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.offset_id = (int) max_id; req.q = ""; req.peer = getInputPeer(did); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_Messages messages = (TLRPC.messages_Messages) response; - TLRPC.TL_photos_photos res = new TLRPC.TL_photos_photos(); - res.count = messages.count; - res.users.addAll(messages.users); - for (int a = 0; a < messages.messages.size(); a++) { - TLRPC.Message message = messages.messages.get(a); - if (message.action == null || message.action.photo == null) { - continue; - } - res.photos.add(message.action.photo); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.messages_Messages messages = (TLRPC.messages_Messages) response; + TLRPC.TL_photos_photos res = new TLRPC.TL_photos_photos(); + res.count = messages.count; + res.users.addAll(messages.users); + for (int a = 0; a < messages.messages.size(); a++) { + TLRPC.Message message = messages.messages.get(a); + if (message.action == null || message.action.photo == null) { + continue; } - processLoadedUserPhotos(res, did, count, max_id, false, classGuid); + res.photos.add(message.action.photo); } + processLoadedUserPhotos(res, did, count, max_id, false, classGuid); } }); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); @@ -1998,10 +1885,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void blockUser(int user_id) { final TLRPC.User user = getUser(user_id); - if (user == null || blockedUsers.contains(user_id)) { + if (user == null || blockedUsers.indexOfKey(user_id) >= 0) { return; } - blockedUsers.add(user_id); + blockedUsers.put(user_id, 1); if (user.bot) { DataQuery.getInstance(currentAccount).removeInline(user_id); } else { @@ -2010,14 +1897,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); TLRPC.TL_contacts_block req = new TLRPC.TL_contacts_block(); req.id = getInputUser(user); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - ArrayList ids = new ArrayList<>(); - ids.add(user.id); - MessagesStorage.getInstance(currentAccount).putBlockedUsers(ids, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + SparseIntArray ids = new SparseIntArray(); + ids.put(user.id, 1); + MessagesStorage.getInstance(currentAccount).putBlockedUsers(ids, false); } }); } @@ -2030,25 +1914,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.channel = getInputChannel(chatId); req.user_id = getInputUser(user); req.banned_rights = rights; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadFullChat(chatId, 0, true); - } - }, 1000); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, parentFragment, req, !isMegagroup); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + } else { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, !isMegagroup)); } }); } @@ -2061,25 +1932,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.channel = getInputChannel(chatId); req.user_id = getInputUser(user); req.admin_rights = rights; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadFullChat(chatId, 0, true); - } - }, 1000); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, parentFragment, req, !isMegagroup); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(() -> loadFullChat(chatId, 0, true), 1000); + } else { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, parentFragment, req, !isMegagroup)); } }); } @@ -2090,15 +1948,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (user == null) { return; } - blockedUsers.remove((Integer) user.id); + blockedUsers.delete(user.id); req.id = getInputUser(user); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - MessagesStorage.getInstance(currentAccount).deleteBlockedUser(user.id); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> MessagesStorage.getInstance(currentAccount).deleteBlockedUser(user.id)); } public void getBlockedUsers(boolean cache) { @@ -2112,44 +1965,38 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_contacts_getBlocked req = new TLRPC.TL_contacts_getBlocked(); req.offset = 0; req.limit = 200; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - ArrayList blocked = new ArrayList<>(); - ArrayList users = null; - if (error == null) { - final TLRPC.contacts_Blocked res = (TLRPC.contacts_Blocked) response; - for (TLRPC.TL_contactBlocked contactBlocked : res.blocked) { - blocked.add(contactBlocked.user_id); - } - users = res.users; - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); - MessagesStorage.getInstance(currentAccount).putBlockedUsers(blocked, true); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + SparseIntArray blocked = new SparseIntArray(); + ArrayList users = null; + if (error == null) { + final TLRPC.contacts_Blocked res = (TLRPC.contacts_Blocked) response; + for (TLRPC.TL_contactBlocked contactBlocked : res.blocked) { + blocked.put(contactBlocked.user_id, 1); } - processLoadedBlockedUsers(blocked, users, false); + users = res.users; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance(currentAccount).putBlockedUsers(blocked, true); } + processLoadedBlockedUsers(blocked, users, false); }); } } - public void processLoadedBlockedUsers(final ArrayList ids, final ArrayList users, final boolean cache) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (users != null) { - putUsers(users, cache); - } - loadingBlockedUsers = false; - if (ids.isEmpty() && cache && !UserConfig.getInstance(currentAccount).blockedUsersLoaded) { - getBlockedUsers(false); - return; - } else if (!cache) { - UserConfig.getInstance(currentAccount).blockedUsersLoaded = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - } - blockedUsers = ids; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); + public void processLoadedBlockedUsers(final SparseIntArray ids, final ArrayList users, final boolean cache) { + AndroidUtilities.runOnUIThread(() -> { + if (users != null) { + putUsers(users, cache); } + loadingBlockedUsers = false; + if (ids.size() == 0 && cache && !UserConfig.getInstance(currentAccount).blockedUsersLoaded) { + getBlockedUsers(false); + return; + } else if (!cache) { + UserConfig.getInstance(currentAccount).blockedUsersLoaded = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + } + blockedUsers = ids; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); }); } @@ -2168,44 +2015,35 @@ public class MessagesController implements NotificationCenter.NotificationCenter user.photo = UserConfig.getInstance(currentAccount).getCurrentUser().photo; NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.User user = getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user == null) { - user = UserConfig.getInstance(currentAccount).getCurrentUser(); - putUser(user, false); - } else { - UserConfig.getInstance(currentAccount).setCurrentUser(user); - } - if (user == null) { - return; - } - MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); - ArrayList users = new ArrayList<>(); - users.add(user); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); - user.photo = (TLRPC.UserProfilePhoto) response; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); - UserConfig.getInstance(currentAccount).saveConfig(true); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.User user1 = getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user1 == null) { + user1 = UserConfig.getInstance(currentAccount).getCurrentUser(); + putUser(user1, false); + } else { + UserConfig.getInstance(currentAccount).setCurrentUser(user1); } + if (user1 == null) { + return; + } + MessagesStorage.getInstance(currentAccount).clearUserPhotos(user1.id); + ArrayList users = new ArrayList<>(); + users.add(user1); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); + user1.photo = (TLRPC.UserProfilePhoto) response; + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + UserConfig.getInstance(currentAccount).saveConfig(true); + }); } }); } else { TLRPC.TL_photos_deletePhotos req = new TLRPC.TL_photos_deletePhotos(); req.id.add(photo); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -2218,12 +2056,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter loadDialogPhotos(did, count, max_id, false, classGuid); return; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(res.users, fromCache); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogPhotosLoaded, did, count, fromCache, classGuid, res.photos); - } + AndroidUtilities.runOnUIThread(() -> { + putUsers(res.users, fromCache); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogPhotosLoaded, did, count, fromCache, classGuid, res.photos); }); } @@ -2303,16 +2138,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter newTaskId = MessagesStorage.getInstance(currentAccount).createPendingTask(data); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewChannelDifferenceParams(res.pts, res.pts_count, channelId); - } - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewChannelDifferenceParams(res.pts, res.pts_count, channelId); + } + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); } else { @@ -2340,16 +2172,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter newTaskId = MessagesStorage.getInstance(currentAccount).createPendingTask(data); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); - } - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); } @@ -2360,13 +2189,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.channel = getInputChannel(chat); req.id = id; req.silent = !notify; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates(updates, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); } }); } @@ -2378,16 +2204,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_deleteUserHistory req = new TLRPC.TL_channels_deleteUserHistory(); req.channel = getInputChannel(chat); req.user_id = getInputUser(user); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; - if (res.offset > 0) { - deleteUserChannelHistory(chat, user, res.offset); - } - processNewChannelDifferenceParams(res.pts, res.pts_count, chat.id); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (res.offset > 0) { + deleteUserChannelHistory(chat, user, res.offset); } + processNewChannelDifferenceParams(res.pts, res.pts_count, chat.id); } }); } @@ -2430,13 +2253,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { dialogs.remove(dialog); if (dialogsServerOnly.remove(dialog) && DialogObject.isChannel(dialog)) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - channelsPts.delete(-(int) did); - shortPollChannels.delete(-(int) did); - needShortPollChannels.delete(-(int) did); - } + Utilities.stageQueue.postRunnable(() -> { + channelsPts.delete(-(int) did); + shortPollChannels.delete(-(int) did); + needShortPollChannels.delete(-(int) did); }); } dialogsGroupsOnly.remove(dialog); @@ -2502,17 +2322,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, false); } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did))); } if (high_id == 1 || onlyHistory == 3) { @@ -2533,11 +2343,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.channel.channel_id = peer.channel_id; req.channel.access_hash = peer.access_hash; req.max_id = max_id_delete > 0 ? max_id_delete : Integer.MAX_VALUE; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }, ConnectionsManager.RequestFlagInvokeAfter); } else { TLRPC.TL_messages_deleteHistory req = new TLRPC.TL_messages_deleteHistory(); @@ -2545,16 +2352,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.max_id = (onlyHistory == 0 ? Integer.MAX_VALUE : max_id_delete); req.just_clear = onlyHistory != 0; final int max_id_delete_final = max_id_delete; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; - if (res.offset > 0) { - deleteDialog(did, false, onlyHistory, max_id_delete_final); - } - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (res.offset > 0) { + deleteDialog(did, false, onlyHistory, max_id_delete_final); } + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -2573,11 +2377,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.id.id = document.id; req.id.access_hash = document.access_hash; req.unsave = false; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -2588,11 +2389,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.id.access_hash = document.access_hash; req.unsave = false; req.attached = asMask; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -2607,24 +2405,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.filter = new TLRPC.TL_channelParticipantsRecent(); req.offset = 0; req.limit = 32; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - putUsers(res.users, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); - MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); - loadedFullParticipants.add(chat_id); - } - loadingFullParticipants.remove(chat_id); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + putUsers(res.users, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); + loadedFullParticipants.add(chat_id); } - }); + loadingFullParticipants.remove(chat_id); + })); } public void loadChatInfo(final int chat_id, CountDownLatch countDownLatch, boolean force) { @@ -2636,15 +2426,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter loadFullChat(chat_id, 0, force); } if (info != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(usersArr, fromCache); - if (info.stickerset != null) { - DataQuery.getInstance(currentAccount).getGroupStickerSetById(info.stickerset); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, byChannelUsers, pinnedMessageObject); + AndroidUtilities.runOnUIThread(() -> { + putUsers(usersArr, fromCache); + if (info.stickerset != null) { + DataQuery.getInstance(currentAccount).getGroupStickerSetById(info.stickerset); } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, byChannelUsers, pinnedMessageObject); }); } } @@ -2667,20 +2454,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus(); req.offline = false; - statusRequest = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - lastStatusUpdateTime = System.currentTimeMillis(); - offlineSent = false; - statusSettingState = 0; - } else { - if (lastStatusUpdateTime != 0) { - lastStatusUpdateTime += 5000; - } + statusRequest = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + lastStatusUpdateTime = System.currentTimeMillis(); + offlineSent = false; + statusSettingState = 0; + } else { + if (lastStatusUpdateTime != 0) { + lastStatusUpdateTime += 5000; } - statusRequest = 0; } + statusRequest = 0; }); } } @@ -2691,18 +2475,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter } TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus(); req.offline = true; - statusRequest = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - offlineSent = true; - } else { - if (lastStatusUpdateTime != 0) { - lastStatusUpdateTime += 5000; - } + statusRequest = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + offlineSent = true; + } else { + if (lastStatusUpdateTime != 0) { + lastStatusUpdateTime += 5000; } - statusRequest = 0; } + statusRequest = 0; }); } @@ -2736,31 +2517,23 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer = getInputPeer(key); req.id = channelViewsToSend.valueAt(a); req.increment = a == 0; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.Vector vector = (TLRPC.Vector) response; - final SparseArray channelViews = new SparseArray<>(); - SparseIntArray array = channelViews.get(key); - if (array == null) { - array = new SparseIntArray(); - channelViews.put(key, array); - } - for (int a = 0; a < req.id.size(); a++) { - if (a >= vector.objects.size()) { - break; - } - array.put(req.id.get(a), (Integer) vector.objects.get(a)); - } - MessagesStorage.getInstance(currentAccount).putChannelViews(channelViews, req.peer instanceof TLRPC.TL_inputPeerChannel); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViews); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.Vector vector = (TLRPC.Vector) response; + final SparseArray channelViews = new SparseArray<>(); + SparseIntArray array = channelViews.get(key); + if (array == null) { + array = new SparseIntArray(); + channelViews.put(key, array); } + for (int a1 = 0; a1 < req.id.size(); a1++) { + if (a1 >= vector.objects.size()) { + break; + } + array.put(req.id.get(a1), (Integer) vector.objects.get(a1)); + } + MessagesStorage.getInstance(currentAccount).putChannelViews(channelViews, req.peer instanceof TLRPC.TL_inputPeerChannel); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViews)); } }); } @@ -2781,12 +2554,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (Integer uid : toRemove) { onlinePrivacy.remove(uid); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS)); } } if (shortPollChannels.size() != 0) { @@ -2833,12 +2601,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter updatePrintingStrings(); if (updated) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT)); } } if (Theme.selectedAutoNightType == Theme.AUTO_NIGHT_TYPE_SCHEDULED && Math.abs(currentTime - lastThemeCheckTime) >= 60) { @@ -2863,37 +2626,24 @@ public class MessagesController implements NotificationCenter.NotificationCenter } checkingTosUpdate = true; TLRPC.TL_help_getTermsOfServiceUpdate req = new TLRPC.TL_help_getTermsOfServiceUpdate(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - checkingTosUpdate = false; - if (response instanceof TLRPC.TL_help_termsOfServiceUpdateEmpty) { - TLRPC.TL_help_termsOfServiceUpdateEmpty res = (TLRPC.TL_help_termsOfServiceUpdateEmpty) response; - nextTosCheckTime = res.expires; - } else if (response instanceof TLRPC.TL_help_termsOfServiceUpdate) { - final TLRPC.TL_help_termsOfServiceUpdate res = (TLRPC.TL_help_termsOfServiceUpdate) response; - nextTosCheckTime = res.expires; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 4, res.terms_of_service); - } - }); - } else { - nextTosCheckTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60 * 60; - } - notificationsPreferences.edit().putInt("nextTosCheckTime", nextTosCheckTime).commit(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + checkingTosUpdate = false; + if (response instanceof TLRPC.TL_help_termsOfServiceUpdateEmpty) { + TLRPC.TL_help_termsOfServiceUpdateEmpty res = (TLRPC.TL_help_termsOfServiceUpdateEmpty) response; + nextTosCheckTime = res.expires; + } else if (response instanceof TLRPC.TL_help_termsOfServiceUpdate) { + final TLRPC.TL_help_termsOfServiceUpdate res = (TLRPC.TL_help_termsOfServiceUpdate) response; + nextTosCheckTime = res.expires; + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 4, res.terms_of_service)); + } else { + nextTosCheckTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60 * 60; } + notificationsPreferences.edit().putInt("nextTosCheckTime", nextTosCheckTime).commit(); }); } public void checkProxyInfo(final boolean reset) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - checkProxyInfoInternal(reset); - } - }); + Utilities.stageQueue.postRunnable(() -> checkProxyInfoInternal(reset)); } private void checkProxyInfoInternal(boolean reset) { @@ -2910,211 +2660,193 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (enabled && !TextUtils.isEmpty(proxyAddress) && !TextUtils.isEmpty(proxySecret)) { checkingProxyInfo = true; TLRPC.TL_help_getProxyData req = new TLRPC.TL_help_getProxyData(); - checkingProxyInfoRequestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (checkingProxyInfoRequestId == 0) { - return; - } - boolean noDialog = false; - if (response instanceof TLRPC.TL_help_proxyDataEmpty) { - TLRPC.TL_help_proxyDataEmpty res = (TLRPC.TL_help_proxyDataEmpty) response; - nextProxyInfoCheckTime = res.expires; - noDialog = true; - } else if (response instanceof TLRPC.TL_help_proxyDataPromo) { - final TLRPC.TL_help_proxyDataPromo res = (TLRPC.TL_help_proxyDataPromo) response; + checkingProxyInfoRequestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (checkingProxyInfoRequestId == 0) { + return; + } + boolean noDialog = false; + if (response instanceof TLRPC.TL_help_proxyDataEmpty) { + TLRPC.TL_help_proxyDataEmpty res = (TLRPC.TL_help_proxyDataEmpty) response; + nextProxyInfoCheckTime = res.expires; + noDialog = true; + } else if (response instanceof TLRPC.TL_help_proxyDataPromo) { + final TLRPC.TL_help_proxyDataPromo res = (TLRPC.TL_help_proxyDataPromo) response; - final long did; - if (res.peer.user_id != 0) { - did = res.peer.user_id; - } else if (res.peer.chat_id != 0) { - did = -res.peer.chat_id; - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat chat = res.chats.get(a); - if (chat.id == res.peer.chat_id) { - if (chat.kicked || chat.restricted) { - noDialog = true; - } - break; - } - } - } else { - did = -res.peer.channel_id; - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat chat = res.chats.get(a); - if (chat.id == res.peer.channel_id) { - if (chat.kicked || chat.restricted) { - noDialog = true; - } - break; + final long did; + if (res.peer.user_id != 0) { + did = res.peer.user_id; + } else if (res.peer.chat_id != 0) { + did = -res.peer.chat_id; + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + if (chat.id == res.peer.chat_id) { + if (chat.kicked || chat.restricted) { + noDialog = true; } + break; } } - proxyDialogId = did; - getGlobalMainSettings().edit().putLong("proxy_dialog", proxyDialogId).commit(); - nextProxyInfoCheckTime = res.expires; - if (!noDialog) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - proxyDialog = dialogs_dict.get(did); + } else { + did = -res.peer.channel_id; + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + if (chat.id == res.peer.channel_id) { + if (chat.kicked || chat.restricted) { + noDialog = true; + } + break; + } + } + } + proxyDialogId = did; + getGlobalMainSettings().edit().putLong("proxy_dialog", proxyDialogId).commit(); + nextProxyInfoCheckTime = res.expires; + if (!noDialog) { + AndroidUtilities.runOnUIThread(() -> { + proxyDialog = dialogs_dict.get(did); - if (proxyDialog != null) { - checkingProxyInfo = false; - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload, true); + if (proxyDialog != null) { + checkingProxyInfo = false; + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload, true); + } else { + final SparseArray usersDict = new SparseArray<>(); + final SparseArray chatsDict = new SparseArray<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User u = res.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat c = res.chats.get(a); + chatsDict.put(c.id, c); + } + + TLRPC.TL_messages_getPeerDialogs req1 = new TLRPC.TL_messages_getPeerDialogs(); + TLRPC.TL_inputDialogPeer peer = new TLRPC.TL_inputDialogPeer(); + if (res.peer.user_id != 0) { + peer.peer = new TLRPC.TL_inputPeerUser(); + peer.peer.user_id = res.peer.user_id; + TLRPC.User user = usersDict.get(res.peer.user_id); + if (user != null) { + peer.peer.access_hash = user.access_hash; + } + } else if (res.peer.chat_id != 0) { + peer.peer = new TLRPC.TL_inputPeerChat(); + peer.peer.chat_id = res.peer.chat_id; + TLRPC.Chat chat = chatsDict.get(res.peer.chat_id); + if (chat != null) { + peer.peer.access_hash = chat.access_hash; + } + } else { + peer.peer = new TLRPC.TL_inputPeerChannel(); + peer.peer.channel_id = res.peer.channel_id; + TLRPC.Chat chat = chatsDict.get(res.peer.channel_id); + if (chat != null) { + peer.peer.access_hash = chat.access_hash; + } + } + + req1.peers.add(peer); + ConnectionsManager.getInstance(currentAccount).sendRequest(req1, (response1, error1) -> { + if (checkingProxyInfoRequestId == 0) { + return; + } + checkingProxyInfoRequestId = 0; + final TLRPC.TL_messages_peerDialogs res2 = (TLRPC.TL_messages_peerDialogs) response1; + if (res2 != null && !res2.dialogs.isEmpty()) { + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + dialogs.chats = res2.chats; + dialogs.users = res2.users; + dialogs.dialogs = res2.dialogs; + dialogs.messages = res2.messages; + MessagesStorage.getInstance(currentAccount).putDialogs(dialogs, 2); + AndroidUtilities.runOnUIThread(() -> { + putUsers(res.users, false); + putChats(res.chats, false); + putUsers(res2.users, false); + putChats(res2.chats, false); + + proxyDialog = res2.dialogs.get(0); + proxyDialog.id = did; + if (DialogObject.isChannel(proxyDialog)) { + channelsPts.put(-(int) proxyDialog.id, proxyDialog.pts); + } + Integer value = dialogs_read_inbox_max.get(proxyDialog.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(proxyDialog.id, Math.max(value, proxyDialog.read_inbox_max_id)); + value = dialogs_read_outbox_max.get(proxyDialog.id); + if (value == null) { + value = 0; + } + dialogs_read_outbox_max.put(proxyDialog.id, Math.max(value, proxyDialog.read_outbox_max_id)); + dialogs_dict.put(did, proxyDialog); + if (!res2.messages.isEmpty()) { + final SparseArray usersDict1 = new SparseArray<>(); + final SparseArray chatsDict1 = new SparseArray<>(); + for (int a = 0; a < res2.users.size(); a++) { + TLRPC.User u = res2.users.get(a); + usersDict1.put(u.id, u); + } + for (int a = 0; a < res2.chats.size(); a++) { + TLRPC.Chat c = res2.chats.get(a); + chatsDict1.put(c.id, c); + } + MessageObject messageObject = new MessageObject(currentAccount, res2.messages.get(0), usersDict1, chatsDict1, false); + dialogMessage.put(did, messageObject); + if (proxyDialog.last_message_date == 0) { + proxyDialog.last_message_date = messageObject.messageOwner.date; + } + } + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload, true); + }); } else { - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User u = res.users.get(a); - usersDict.put(u.id, u); - } - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat c = res.chats.get(a); - chatsDict.put(c.id, c); - } - - TLRPC.TL_messages_getPeerDialogs req = new TLRPC.TL_messages_getPeerDialogs(); - TLRPC.TL_inputDialogPeer peer = new TLRPC.TL_inputDialogPeer(); - if (res.peer.user_id != 0) { - peer.peer = new TLRPC.TL_inputPeerUser(); - peer.peer.user_id = res.peer.user_id; - TLRPC.User user = usersDict.get(res.peer.user_id); - if (user != null) { - peer.peer.access_hash = user.access_hash; - } - } else if (res.peer.chat_id != 0) { - peer.peer = new TLRPC.TL_inputPeerChat(); - peer.peer.chat_id = res.peer.chat_id; - TLRPC.Chat chat = chatsDict.get(res.peer.chat_id); - if (chat != null) { - peer.peer.access_hash = chat.access_hash; - } - } else { - peer.peer = new TLRPC.TL_inputPeerChannel(); - peer.peer.channel_id = res.peer.channel_id; - TLRPC.Chat chat = chatsDict.get(res.peer.channel_id); - if (chat != null) { - peer.peer.access_hash = chat.access_hash; - } - } - - req.peers.add(peer); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (checkingProxyInfoRequestId == 0) { - return; + AndroidUtilities.runOnUIThread(() -> { + if (proxyDialog != null) { + if (proxyDialog.id < 0) { + TLRPC.Chat chat = getChat(-(int) proxyDialog.id); + if (chat == null || chat.left || chat.kicked || chat.restricted) { + dialogs_dict.remove(proxyDialog.id); + dialogs.remove(proxyDialog); + } } - checkingProxyInfoRequestId = 0; - final TLRPC.TL_messages_peerDialogs res2 = (TLRPC.TL_messages_peerDialogs) response; - if (res2 != null && !res2.dialogs.isEmpty()) { - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); - dialogs.chats = res2.chats; - dialogs.users = res2.users; - dialogs.dialogs = res2.dialogs; - dialogs.messages = res2.messages; - MessagesStorage.getInstance(currentAccount).putDialogs(dialogs, 2); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(res.users, false); - putChats(res.chats, false); - putUsers(res2.users, false); - putChats(res2.chats, false); - - proxyDialog = res2.dialogs.get(0); - proxyDialog.id = did; - if (DialogObject.isChannel(proxyDialog)) { - channelsPts.put(-(int) proxyDialog.id, proxyDialog.pts); - } - Integer value = dialogs_read_inbox_max.get(proxyDialog.id); - if (value == null) { - value = 0; - } - dialogs_read_inbox_max.put(proxyDialog.id, Math.max(value, proxyDialog.read_inbox_max_id)); - value = dialogs_read_outbox_max.get(proxyDialog.id); - if (value == null) { - value = 0; - } - dialogs_read_outbox_max.put(proxyDialog.id, Math.max(value, proxyDialog.read_outbox_max_id)); - dialogs_dict.put(did, proxyDialog); - if (!res2.messages.isEmpty()) { - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); - for (int a = 0; a < res2.users.size(); a++) { - TLRPC.User u = res2.users.get(a); - usersDict.put(u.id, u); - } - for (int a = 0; a < res2.chats.size(); a++) { - TLRPC.Chat c = res2.chats.get(a); - chatsDict.put(c.id, c); - } - MessageObject messageObject = new MessageObject(currentAccount, res2.messages.get(0), usersDict, chatsDict, false); - dialogMessage.put(did, messageObject); - if (proxyDialog.last_message_date == 0) { - proxyDialog.last_message_date = messageObject.messageOwner.date; - } - } - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload, true); - } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (proxyDialog != null) { - if (proxyDialog.id < 0) { - TLRPC.Chat chat = getChat(-(int) proxyDialog.id); - if (chat == null || chat.left || chat.kicked || chat.restricted) { - dialogs_dict.remove(proxyDialog.id); - dialogs.remove(proxyDialog); - } - } - proxyDialog = null; - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - } - }); - } - checkingProxyInfo = false; + proxyDialog = null; + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } }); } - } - }); - } - } else { - nextProxyInfoCheckTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60 * 60; - noDialog = true; - } - if (noDialog) { - proxyDialogId = 0; - getGlobalMainSettings().edit().putLong("proxy_dialog", proxyDialogId).commit(); - checkingProxyInfoRequestId = 0; - checkingProxyInfo = false; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (proxyDialog != null) { - if (proxyDialog.id < 0) { - TLRPC.Chat chat = getChat(-(int) proxyDialog.id); - if (chat == null || chat.left || chat.kicked || chat.restricted) { - dialogs_dict.remove(proxyDialog.id); - dialogs.remove(proxyDialog); - } - } - proxyDialog = null; - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } + checkingProxyInfo = false; + }); } }); } + } else { + nextProxyInfoCheckTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 60 * 60; + noDialog = true; + } + if (noDialog) { + proxyDialogId = 0; + getGlobalMainSettings().edit().putLong("proxy_dialog", proxyDialogId).commit(); + checkingProxyInfoRequestId = 0; + checkingProxyInfo = false; + AndroidUtilities.runOnUIThread(() -> { + if (proxyDialog != null) { + if (proxyDialog.id < 0) { + TLRPC.Chat chat = getChat(-(int) proxyDialog.id); + if (chat == null || chat.left || chat.kicked || chat.restricted) { + dialogs_dict.remove(proxyDialog.id); + dialogs.remove(proxyDialog); + } + } + proxyDialog = null; + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); } }); } else { @@ -3126,21 +2858,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter ConnectionsManager.getInstance(currentAccount).cancelRequest(checkingProxyInfoRequestId, true); checkingProxyInfoRequestId = 0; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (proxyDialog != null) { - if (proxyDialog.id < 0) { - TLRPC.Chat chat = getChat(-(int) proxyDialog.id); - if (chat == null || chat.left || chat.kicked || chat.restricted) { - dialogs_dict.remove(proxyDialog.id); - dialogs.remove(proxyDialog); - } + AndroidUtilities.runOnUIThread(() -> { + if (proxyDialog != null) { + if (proxyDialog.id < 0) { + TLRPC.Chat chat = getChat(-(int) proxyDialog.id); + if (chat == null || chat.left || chat.kicked || chat.restricted) { + dialogs_dict.remove(proxyDialog.id); + dialogs.remove(proxyDialog); } - proxyDialog = null; - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } + proxyDialog = null; + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } }); } @@ -3270,12 +2999,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter lastPrintingStringCount = newPrintingStrings.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - printingStrings = newPrintingStrings; - printingStringsTypes = newPrintingStringsTypes; - } + AndroidUtilities.runOnUIThread(() -> { + printingStrings = newPrintingStrings; + printingStringsTypes = newPrintingStringsTypes; }); } @@ -3338,20 +3064,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.action = new TLRPC.TL_sendMessageUploadAudioAction(); } typings.put(dialog_id, true); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - LongSparseArray typings = sendingTypings.get(action); - if (typings != null) { - typings.remove(dialog_id); - } - } - }); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + LongSparseArray typings1 = sendingTypings.get(action); + if (typings1 != null) { + typings1.remove(dialog_id); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); if (classGuid != 0) { ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -3367,20 +3085,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer.access_hash = chat.access_hash; req.typing = true; typings.put(dialog_id, true); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - LongSparseArray typings = sendingTypings.get(action); - if (typings != null) { - typings.remove(dialog_id); - } - } - }); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + LongSparseArray typings12 = sendingTypings.get(action); + if (typings12 != null) { + typings12.remove(dialog_id); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); if (classGuid != 0) { ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -3411,25 +3121,22 @@ public class MessagesController implements NotificationCenter.NotificationCenter inputDialogPeer.peer = inputPeer; req.peers.add(inputDialogPeer); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; - if (!res.dialogs.isEmpty()) { - TLRPC.TL_dialog dialog = res.dialogs.get(0); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; + if (!res.dialogs.isEmpty()) { + TLRPC.TL_dialog dialog = res.dialogs.get(0); - if (dialog.top_message != 0) { - TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); - dialogs.chats = res.chats; - dialogs.users = res.users; - dialogs.dialogs = res.dialogs; - dialogs.messages = res.messages; - MessagesStorage.getInstance(currentAccount).putDialogs(dialogs, 0); - } - - loadMessagesInternal(dialog_id, count, max_id, offset_date, false, midDate, classGuid, load_type, dialog.top_message, isChannel, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false); + if (dialog.top_message != 0) { + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + dialogs.chats = res.chats; + dialogs.users = res.users; + dialogs.dialogs = res.dialogs; + dialogs.messages = res.messages; + MessagesStorage.getInstance(currentAccount).putDialogs(dialogs, 0); } + + loadMessagesInternal(dialog_id, count, max_id, offset_date, false, midDate, classGuid, load_type, dialog.top_message, isChannel, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false); } } }); @@ -3457,27 +3164,24 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.limit = count; req.offset_id = max_id; req.offset_date = offset_date; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - if (res.messages.size() > count) { - res.messages.remove(0); - } - int mid = max_id; - if (offset_date != 0 && !res.messages.isEmpty()) { - mid = res.messages.get(res.messages.size() - 1).id; - for (int a = res.messages.size() - 1; a >= 0; a--) { - TLRPC.Message message = res.messages.get(a); - if (message.date > offset_date) { - mid = message.id; - break; - } + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (res.messages.size() > count) { + res.messages.remove(0); + } + int mid = max_id; + if (offset_date != 0 && !res.messages.isEmpty()) { + mid = res.messages.get(res.messages.size() - 1).id; + for (int a = res.messages.size() - 1; a >= 0; a--) { + TLRPC.Message message = res.messages.get(a); + if (message.date > offset_date) { + mid = message.id; + break; } } - processLoadedMessages(res, dialog_id, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, loadIndex, queryFromServer, mentionsCount); } + processLoadedMessages(res, dialog_id, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, loadIndex, queryFromServer, mentionsCount); } }); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); @@ -3496,44 +3200,36 @@ public class MessagesController implements NotificationCenter.NotificationCenter arrayList.addAll(messages); TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); req.message = url; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - ArrayList arrayList = reloadingWebpages.remove(url); - if (arrayList == null) { - return; - } - TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); - if (!(response instanceof TLRPC.TL_messageMediaWebPage)) { - for (int a = 0; a < arrayList.size(); a++) { - arrayList.get(a).messageOwner.media.webpage = new TLRPC.TL_webPageEmpty(); - messagesRes.messages.add(arrayList.get(a).messageOwner); - } - } else { - TLRPC.TL_messageMediaWebPage media = (TLRPC.TL_messageMediaWebPage) response; - if (media.webpage instanceof TLRPC.TL_webPage || media.webpage instanceof TLRPC.TL_webPageEmpty) { - for (int a = 0; a < arrayList.size(); a++) { - arrayList.get(a).messageOwner.media.webpage = media.webpage; - if (a == 0) { - ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); - } - messagesRes.messages.add(arrayList.get(a).messageOwner); - } - } else { - reloadingWebpagesPending.put(media.webpage.id, arrayList); - } - } - if (!messagesRes.messages.isEmpty()) { - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, -2, 0, false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + ArrayList arrayList1 = reloadingWebpages.remove(url); + if (arrayList1 == null) { + return; } - }); + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + if (!(response instanceof TLRPC.TL_messageMediaWebPage)) { + for (int a = 0; a < arrayList1.size(); a++) { + arrayList1.get(a).messageOwner.media.webpage = new TLRPC.TL_webPageEmpty(); + messagesRes.messages.add(arrayList1.get(a).messageOwner); + } + } else { + TLRPC.TL_messageMediaWebPage media = (TLRPC.TL_messageMediaWebPage) response; + if (media.webpage instanceof TLRPC.TL_webPage || media.webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0; a < arrayList1.size(); a++) { + arrayList1.get(a).messageOwner.media.webpage = media.webpage; + if (a == 0) { + ImageLoader.saveMessageThumbs(arrayList1.get(a).messageOwner); + } + messagesRes.messages.add(arrayList1.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(media.webpage.id, arrayList1); + } + } + if (!messagesRes.messages.isEmpty()) { + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, -2, 0, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList1); + } + })); } } @@ -3542,149 +3238,138 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (BuildVars.LOGS_ENABLED) { FileLog.d("processLoadedMessages size " + messagesRes.messages.size() + " in chat " + dialog_id + " count " + count + " max_id " + max_id + " cache " + isCache + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " isChannel " + isChannel + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - boolean createDialog = false; - boolean isMegagroup = false; - if (messagesRes instanceof TLRPC.TL_messages_channelMessages) { - int channelId = -(int) dialog_id; - int channelPts = channelsPts.get(channelId); + Utilities.stageQueue.postRunnable(() -> { + boolean createDialog = false; + boolean isMegagroup = false; + if (messagesRes instanceof TLRPC.TL_messages_channelMessages) { + int channelId = -(int) dialog_id; + int channelPts = channelsPts.get(channelId); + if (channelPts == 0) { + channelPts = MessagesStorage.getInstance(currentAccount).getChannelPtsSync(channelId); if (channelPts == 0) { - channelPts = MessagesStorage.getInstance(currentAccount).getChannelPtsSync(channelId); - if (channelPts == 0) { - channelsPts.put(channelId, messagesRes.pts); - createDialog = true; - if (needShortPollChannels.indexOfKey(channelId) >= 0 && shortPollChannels.indexOfKey(channelId) < 0) { - getChannelDifference(channelId, 2, 0, null); - } else { - getChannelDifference(channelId); - } + channelsPts.put(channelId, messagesRes.pts); + createDialog = true; + if (needShortPollChannels.indexOfKey(channelId) >= 0 && shortPollChannels.indexOfKey(channelId) < 0) { + getChannelDifference(channelId, 2, 0, null); + } else { + getChannelDifference(channelId); } } - for (int a = 0; a < messagesRes.chats.size(); a++) { - TLRPC.Chat chat = messagesRes.chats.get(a); - if (chat.id == channelId) { - isMegagroup = chat.megagroup; - break; - } - } - } - int lower_id = (int) dialog_id; - int high_id = (int) (dialog_id >> 32); - if (!isCache) { - ImageLoader.saveMessagesThumbs(messagesRes.messages); - } - if (high_id != 1 && lower_id != 0 && isCache && messagesRes.messages.size() == 0) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadMessages(dialog_id, count, load_type == 2 && queryFromServer ? first_unread : max_id, offset_date, false, 0, classGuid, load_type, last_message_id, isChannel, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount); - } - }); - return; - } - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); - for (int a = 0; a < messagesRes.users.size(); a++) { - TLRPC.User u = messagesRes.users.get(a); - usersDict.put(u.id, u); } for (int a = 0; a < messagesRes.chats.size(); a++) { - TLRPC.Chat c = messagesRes.chats.get(a); - chatsDict.put(c.id, c); + TLRPC.Chat chat = messagesRes.chats.get(a); + if (chat.id == channelId) { + isMegagroup = chat.megagroup; + break; + } } - int size = messagesRes.messages.size(); - if (!isCache) { - Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); - if (inboxValue == null) { - inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); - dialogs_read_inbox_max.put(dialog_id, inboxValue); - } - - Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); - if (outboxValue == null) { - outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); - dialogs_read_outbox_max.put(dialog_id, outboxValue); - } - - for (int a = 0; a < size; a++) { - TLRPC.Message message = messagesRes.messages.get(a); - if (isMegagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - - if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { - TLRPC.User user = usersDict.get(message.action.user_id); - if (user != null && user.bot) { - message.reply_markup = new TLRPC.TL_replyKeyboardHide(); - message.flags |= 64; - } - } - if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { - message.unread = false; - message.media_unread = false; - } else { - message.unread = (message.out ? outboxValue : inboxValue) < message.id; - } - } - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, load_type, max_id, createDialog); + } + int lower_id = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (!isCache) { + ImageLoader.saveMessagesThumbs(messagesRes.messages); + } + if (high_id != 1 && lower_id != 0 && isCache && messagesRes.messages.size() == 0) { + AndroidUtilities.runOnUIThread(() -> loadMessages(dialog_id, count, load_type == 2 && queryFromServer ? first_unread : max_id, offset_date, false, 0, classGuid, load_type, last_message_id, isChannel, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount)); + return; + } + final SparseArray usersDict = new SparseArray<>(); + final SparseArray chatsDict = new SparseArray<>(); + for (int a = 0; a < messagesRes.users.size(); a++) { + TLRPC.User u = messagesRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < messagesRes.chats.size(); a++) { + TLRPC.Chat c = messagesRes.chats.get(a); + chatsDict.put(c.id, c); + } + int size = messagesRes.messages.size(); + if (!isCache) { + Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); + if (inboxValue == null) { + inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); + dialogs_read_inbox_max.put(dialog_id, inboxValue); } - final ArrayList objects = new ArrayList<>(); - final ArrayList messagesToReload = new ArrayList<>(); - final HashMap> webpagesToReload = new HashMap<>(); - TLRPC.InputChannel inputChannel = null; + + Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); + if (outboxValue == null) { + outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); + dialogs_read_outbox_max.put(dialog_id, outboxValue); + } + for (int a = 0; a < size; a++) { TLRPC.Message message = messagesRes.messages.get(a); - message.dialog_id = dialog_id; - MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, true); - objects.add(messageObject); - if (isCache) { - if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { - if (message.media.bytes != null && (message.media.bytes.length == 0 || message.media.bytes.length == 1 && message.media.bytes[0] < TLRPC.LAYER)) { - messagesToReload.add(message.id); - } - } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { - if (message.media.webpage instanceof TLRPC.TL_webPagePending && message.media.webpage.date <= ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { - messagesToReload.add(message.id); - } else if (message.media.webpage instanceof TLRPC.TL_webPageUrlPending) { - ArrayList arrayList = webpagesToReload.get(message.media.webpage.url); - if (arrayList == null) { - arrayList = new ArrayList<>(); - webpagesToReload.put(message.media.webpage.url, arrayList); - } - arrayList.add(messageObject); + if (isMegagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + message.flags |= 64; + } + } + if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } else { + message.unread = (message.out ? outboxValue : inboxValue) < message.id; + } + } + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, dialog_id, load_type, max_id, createDialog); + } + final ArrayList objects = new ArrayList<>(); + final ArrayList messagesToReload = new ArrayList<>(); + final HashMap> webpagesToReload = new HashMap<>(); + TLRPC.InputChannel inputChannel = null; + for (int a = 0; a < size; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + message.dialog_id = dialog_id; + MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, true); + objects.add(messageObject); + if (isCache) { + if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { + if (message.media.bytes != null && (message.media.bytes.length == 0 || message.media.bytes.length == 1 && message.media.bytes[0] < TLRPC.LAYER)) { + messagesToReload.add(message.id); + } + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (message.media.webpage instanceof TLRPC.TL_webPagePending && message.media.webpage.date <= ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { + messagesToReload.add(message.id); + } else if (message.media.webpage instanceof TLRPC.TL_webPageUrlPending) { + ArrayList arrayList = webpagesToReload.get(message.media.webpage.url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + webpagesToReload.put(message.media.webpage.url, arrayList); } + arrayList.add(messageObject); } } } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(messagesRes.users, isCache); - putChats(messagesRes.chats, isCache); - int first_unread_final = Integer.MAX_VALUE; - if (queryFromServer && load_type == 2) { - for (int a = 0; a < messagesRes.messages.size(); a++) { - TLRPC.Message message = messagesRes.messages.get(a); - if (!message.out && message.id > first_unread && message.id < first_unread_final) { - first_unread_final = message.id; - } - } - } - if (first_unread_final == Integer.MAX_VALUE) { - first_unread_final = first_unread; - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount); - if (!messagesToReload.isEmpty()) { - reloadMessages(messagesToReload, dialog_id); - } - if (!webpagesToReload.isEmpty()) { - reloadWebPages(dialog_id, webpagesToReload); + } + AndroidUtilities.runOnUIThread(() -> { + putUsers(messagesRes.users, isCache); + putChats(messagesRes.chats, isCache); + int first_unread_final = Integer.MAX_VALUE; + if (queryFromServer && load_type == 2) { + for (int a = 0; a < messagesRes.messages.size(); a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (!message.out && message.id > first_unread && message.id < first_unread_final) { + first_unread_final = message.id; } } - }); - } + } + if (first_unread_final == Integer.MAX_VALUE) { + first_unread_final = first_unread; + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount); + if (!messagesToReload.isEmpty()) { + reloadMessages(messagesToReload, dialog_id); + } + if (!webpagesToReload.isEmpty()) { + reloadWebPages(dialog_id, webpagesToReload); + } + }); }); } @@ -3694,26 +3379,20 @@ public class MessagesController implements NotificationCenter.NotificationCenter } TLRPC.TL_help_getRecentMeUrls req = new TLRPC.TL_help_getRecentMeUrls(); req.referer = installReferer; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (error == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - /*installReferer = null; - mainPreferences.edit().remove("installReferer").commit();*/ + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + AndroidUtilities.runOnUIThread(() -> { + /*installReferer = null; + mainPreferences.edit().remove("installReferer").commit();*/ - TLRPC.TL_help_recentMeUrls res = (TLRPC.TL_help_recentMeUrls) response; - putUsers(res.users, false); - putChats(res.chats, false); - hintDialogs.clear(); - hintDialogs.addAll(res.urls); + TLRPC.TL_help_recentMeUrls res = (TLRPC.TL_help_recentMeUrls) response; + putUsers(res.users, false); + putChats(res.chats, false); + hintDialogs.clear(); + hintDialogs.addAll(res.urls); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - }); - } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); } }); } @@ -3790,13 +3469,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.offset_peer = new TLRPC.TL_inputPeerEmpty(); } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; - processLoadedDialogs(dialogsRes, null, 0, count, 0, false, false, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; + processLoadedDialogs(dialogsRes, null, 0, count, 0, false, false, false); } }); } @@ -3815,55 +3491,47 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer = new TLRPC.TL_inputNotifyUsers(); } final int type = a; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - loadingNotificationSettings--; - TLRPC.TL_peerNotifySettings notify_settings = (TLRPC.TL_peerNotifySettings) response; - SharedPreferences.Editor editor = notificationsPreferences.edit(); - if (type == 0) { - if ((notify_settings.flags & 1) != 0) { - editor.putBoolean("EnablePreviewGroup", notify_settings.show_previews); - } - if ((notify_settings.flags & 2) != 0) { - /*if (notify_settings.silent) { - editor.putString("GroupSoundPath", "NoSound"); - } else { - editor.remove("GroupSoundPath"); - }*/ - } - if ((notify_settings.flags & 4) != 0) { - editor.putBoolean("EnableGroup", notify_settings.mute_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime()); - } - } else { - if ((notify_settings.flags & 1) != 0) { - editor.putBoolean("EnablePreviewAll", notify_settings.show_previews); - } - if ((notify_settings.flags & 2) != 0) { - /*if (notify_settings.silent) { - editor.putString("GlobalSoundPath", "NoSound"); - } else { - editor.remove("GlobalSoundPath"); - }*/ - } - if ((notify_settings.flags & 4) != 0) { - editor.putBoolean("EnableAll", notify_settings.mute_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime()); - } - } - editor.commit(); - if (loadingNotificationSettings == 0) { - UserConfig.getInstance(currentAccount).notificationsSettingsLoaded = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + loadingNotificationSettings--; + TLRPC.TL_peerNotifySettings notify_settings = (TLRPC.TL_peerNotifySettings) response; + SharedPreferences.Editor editor = notificationsPreferences.edit(); + if (type == 0) { + if ((notify_settings.flags & 1) != 0) { + editor.putBoolean("EnablePreviewGroup", notify_settings.show_previews); } - }); + if ((notify_settings.flags & 2) != 0) { + /*if (notify_settings.silent) { + editor.putString("GroupSoundPath", "NoSound"); + } else { + editor.remove("GroupSoundPath"); + }*/ + } + if ((notify_settings.flags & 4) != 0) { + editor.putBoolean("EnableGroup", notify_settings.mute_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + } + } else { + if ((notify_settings.flags & 1) != 0) { + editor.putBoolean("EnablePreviewAll", notify_settings.show_previews); + } + if ((notify_settings.flags & 2) != 0) { + /*if (notify_settings.silent) { + editor.putString("GlobalSoundPath", "NoSound"); + } else { + editor.remove("GlobalSoundPath"); + }*/ + } + if ((notify_settings.flags & 4) != 0) { + editor.putBoolean("EnableAll", notify_settings.mute_until < ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + } + } + editor.commit(); + if (loadingNotificationSettings == 0) { + UserConfig.getInstance(currentAccount).notificationsSettingsLoaded = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + } } - }); + })); } } @@ -3878,26 +3546,20 @@ public class MessagesController implements NotificationCenter.NotificationCenter } resetingDialogs = true; TLRPC.TL_messages_getPinnedDialogs req = new TLRPC.TL_messages_getPinnedDialogs(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - resetDialogsPinned = (TLRPC.TL_messages_peerDialogs) response; - resetDialogs(false, seq, newPts, date, qts); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + resetDialogsPinned = (TLRPC.TL_messages_peerDialogs) response; + resetDialogs(false, seq, newPts, date, qts); } }); TLRPC.TL_messages_getDialogs req2 = new TLRPC.TL_messages_getDialogs(); req2.limit = 100; req2.exclude_pinned = true; req2.offset_peer = new TLRPC.TL_inputPeerEmpty(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - resetDialogsAll = (TLRPC.messages_Dialogs) response; - resetDialogs(false, seq, newPts, date, qts); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response, error) -> { + if (error == null) { + resetDialogsAll = (TLRPC.messages_Dialogs) response; + resetDialogs(false, seq, newPts, date, qts); } }); } else if (resetDialogsPinned != null && resetDialogsAll != null) { @@ -4027,74 +3689,68 @@ public class MessagesController implements NotificationCenter.NotificationCenter } protected void completeDialogsReset(final TLRPC.messages_Dialogs dialogsRes, final int messagesCount, final int seq, final int newPts, final int date, final int qts, final LongSparseArray new_dialogs_dict, final LongSparseArray new_dialogMessage, final TLRPC.Message lastMessage) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - gettingDifference = false; - MessagesStorage.getInstance(currentAccount).setLastPtsValue(newPts); - MessagesStorage.getInstance(currentAccount).setLastDateValue(date); - MessagesStorage.getInstance(currentAccount).setLastQtsValue(qts); - getDifference(); + Utilities.stageQueue.postRunnable(() -> { + gettingDifference = false; + MessagesStorage.getInstance(currentAccount).setLastPtsValue(newPts); + MessagesStorage.getInstance(currentAccount).setLastDateValue(date); + MessagesStorage.getInstance(currentAccount).setLastQtsValue(qts); + getDifference(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - resetingDialogs = false; - applyDialogsNotificationsSettings(dialogsRes.dialogs); - if (!UserConfig.getInstance(currentAccount).draftsLoaded) { - DataQuery.getInstance(currentAccount).loadDrafts(); - } + AndroidUtilities.runOnUIThread(() -> { + resetingDialogs = false; + applyDialogsNotificationsSettings(dialogsRes.dialogs); + if (!UserConfig.getInstance(currentAccount).draftsLoaded) { + DataQuery.getInstance(currentAccount).loadDrafts(); + } - putUsers(dialogsRes.users, false); - putChats(dialogsRes.chats, false); + putUsers(dialogsRes.users, false); + putChats(dialogsRes.chats, false); - for (int a = 0; a < dialogs.size(); a++) { - TLRPC.TL_dialog oldDialog = dialogs.get(a); - if ((int) oldDialog.id != 0) { - dialogs_dict.remove(oldDialog.id); - MessageObject messageObject = dialogMessage.get(oldDialog.id); - dialogMessage.remove(oldDialog.id); - if (messageObject != null) { - dialogMessagesByIds.remove(messageObject.getId()); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.remove(messageObject.messageOwner.random_id); - } - } + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.TL_dialog oldDialog = dialogs.get(a); + if ((int) oldDialog.id != 0) { + dialogs_dict.remove(oldDialog.id); + MessageObject messageObject = dialogMessage.get(oldDialog.id); + dialogMessage.remove(oldDialog.id); + if (messageObject != null) { + dialogMessagesByIds.remove(messageObject.getId()); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(messageObject.messageOwner.random_id); } } - - for (int a = 0; a < new_dialogs_dict.size(); a++) { - long key = new_dialogs_dict.keyAt(a); - TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); - if (value.draft instanceof TLRPC.TL_draftMessage) { - DataQuery.getInstance(currentAccount).saveDraft(value.id, value.draft, null, false); - } - dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } - } - - dialogs.clear(); - for (int a = 0, size = dialogs_dict.size(); a < size; a++) { - dialogs.add(dialogs_dict.valueAt(a)); - } - sortDialogs(null); - dialogsEndReached = true; - serverDialogsEndReached = false; - - if (UserConfig.getInstance(currentAccount).totalDialogsLoadCount < 400 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != Integer.MAX_VALUE) { - loadDialogs(0, 100, false); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } - }); - } + } + + for (int a = 0; a < new_dialogs_dict.size(); a++) { + long key = new_dialogs_dict.keyAt(a); + TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); + if (value.draft instanceof TLRPC.TL_draftMessage) { + DataQuery.getInstance(currentAccount).saveDraft(value.id, value.draft, null, false); + } + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + } + + dialogs.clear(); + for (int a = 0, size = dialogs_dict.size(); a < size; a++) { + dialogs.add(dialogs_dict.valueAt(a)); + } + sortDialogs(null); + dialogsEndReached = true; + serverDialogsEndReached = false; + + if (UserConfig.getInstance(currentAccount).totalDialogsLoadCount < 400 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != Integer.MAX_VALUE) { + loadDialogs(0, 100, false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); }); } @@ -4127,116 +3783,90 @@ public class MessagesController implements NotificationCenter.NotificationCenter } req.offset_peer.access_hash = accessPeer; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - int offsetId; - UserConfig.getInstance(currentAccount).totalDialogsLoadCount += dialogsRes.dialogs.size(); - TLRPC.Message lastMessage = null; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + int offsetId; + UserConfig.getInstance(currentAccount).totalDialogsLoadCount += dialogsRes.dialogs.size(); + TLRPC.Message lastMessage = null; + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("search migrate id " + message.id + " date " + LocaleController.getInstance().formatterStats.format((long) message.date * 1000)); + } + if (lastMessage == null || message.date < lastMessage.date) { + lastMessage = message; + } + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("migrate step with id " + lastMessage.id + " date " + LocaleController.getInstance().formatterStats.format((long) lastMessage.date * 1000)); + } + if (dialogsRes.dialogs.size() >= 100) { + offsetId = lastMessage.id; + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("migrate stop due to not 100 dialogs"); + } + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = UserConfig.getInstance(currentAccount).migrateOffsetDate; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = UserConfig.getInstance(currentAccount).migrateOffsetUserId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = UserConfig.getInstance(currentAccount).migrateOffsetChatId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = UserConfig.getInstance(currentAccount).migrateOffsetChannelId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = UserConfig.getInstance(currentAccount).migrateOffsetAccess; + offsetId = -1; + } + + StringBuilder dids = new StringBuilder(dialogsRes.dialogs.size() * 12); + LongSparseArray dialogHashMap = new LongSparseArray<>(); + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(a); + if (dialog.peer.channel_id != 0) { + dialog.id = -dialog.peer.channel_id; + } else if (dialog.peer.chat_id != 0) { + dialog.id = -dialog.peer.chat_id; + } else { + dialog.id = dialog.peer.user_id; + } + if (dids.length() > 0) { + dids.append(","); + } + dids.append(dialog.id); + dialogHashMap.put(dialog.id, dialog); + } + SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE did IN (%s)", dids.toString())); + while (cursor.next()) { + long did = cursor.longValue(0); + TLRPC.TL_dialog dialog = dialogHashMap.get(did); + dialogHashMap.remove(did); + if (dialog != null) { + dialogsRes.dialogs.remove(dialog); for (int a = 0; a < dialogsRes.messages.size(); a++) { TLRPC.Message message = dialogsRes.messages.get(a); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("search migrate id " + message.id + " date " + LocaleController.getInstance().formatterStats.format((long) message.date * 1000)); + if (MessageObject.getDialogId(message) != did) { + continue; } - if (lastMessage == null || message.date < lastMessage.date) { - lastMessage = message; + dialogsRes.messages.remove(a); + a--; + if (message.id == dialog.top_message) { + dialog.top_message = 0; + break; } } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("migrate step with id " + lastMessage.id + " date " + LocaleController.getInstance().formatterStats.format((long) lastMessage.date * 1000)); - } - if (dialogsRes.dialogs.size() >= 100) { - offsetId = lastMessage.id; - } else { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("migrate stop due to not 100 dialogs"); - } - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = UserConfig.getInstance(currentAccount).migrateOffsetDate; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = UserConfig.getInstance(currentAccount).migrateOffsetUserId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = UserConfig.getInstance(currentAccount).migrateOffsetChatId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = UserConfig.getInstance(currentAccount).migrateOffsetChannelId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = UserConfig.getInstance(currentAccount).migrateOffsetAccess; - offsetId = -1; - } - - StringBuilder dids = new StringBuilder(dialogsRes.dialogs.size() * 12); - LongSparseArray dialogHashMap = new LongSparseArray<>(); - for (int a = 0; a < dialogsRes.dialogs.size(); a++) { - TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(a); - if (dialog.peer.channel_id != 0) { - dialog.id = -dialog.peer.channel_id; - } else if (dialog.peer.chat_id != 0) { - dialog.id = -dialog.peer.chat_id; - } else { - dialog.id = dialog.peer.user_id; - } - if (dids.length() > 0) { - dids.append(","); - } - dids.append(dialog.id); - dialogHashMap.put(dialog.id, dialog); - } - SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE did IN (%s)", dids.toString())); - while (cursor.next()) { - long did = cursor.longValue(0); - TLRPC.TL_dialog dialog = dialogHashMap.get(did); - dialogHashMap.remove(did); - if (dialog != null) { - dialogsRes.dialogs.remove(dialog); - for (int a = 0; a < dialogsRes.messages.size(); a++) { - TLRPC.Message message = dialogsRes.messages.get(a); - if (MessageObject.getDialogId(message) != did) { - continue; - } - dialogsRes.messages.remove(a); - a--; - if (message.id == dialog.top_message) { - dialog.top_message = 0; - break; - } - } - } - } - cursor.dispose(); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("migrate found missing dialogs " + dialogsRes.dialogs.size()); - } - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT min(date) FROM dialogs WHERE date != 0 AND did >> 32 IN (0, -1)"); - if (cursor.next()) { - int date = Math.max(1441062000, cursor.intValue(0)); - for (int a = 0; a < dialogsRes.messages.size(); a++) { - TLRPC.Message message = dialogsRes.messages.get(a); - if (message.date < date) { - if (offset != -1) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = UserConfig.getInstance(currentAccount).migrateOffsetId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = UserConfig.getInstance(currentAccount).migrateOffsetDate; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = UserConfig.getInstance(currentAccount).migrateOffsetUserId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = UserConfig.getInstance(currentAccount).migrateOffsetChatId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = UserConfig.getInstance(currentAccount).migrateOffsetChannelId; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = UserConfig.getInstance(currentAccount).migrateOffsetAccess; - offsetId = -1; - if (BuildVars.LOGS_ENABLED) { - FileLog.d("migrate stop due to reached loaded dialogs " + LocaleController.getInstance().formatterStats.format((long) date * 1000)); - } - } - dialogsRes.messages.remove(a); - a--; - long did = MessageObject.getDialogId(message); - TLRPC.TL_dialog dialog = dialogHashMap.get(did); - dialogHashMap.remove(did); - if (dialog != null) { - dialogsRes.dialogs.remove(dialog); - } - } - } - if (lastMessage != null && lastMessage.date < date && offset != -1) { + } + } + cursor.dispose(); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("migrate found missing dialogs " + dialogsRes.dialogs.size()); + } + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT min(date) FROM dialogs WHERE date != 0 AND did >> 32 IN (0, -1)"); + if (cursor.next()) { + int date = Math.max(1441062000, cursor.intValue(0)); + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (message.date < date) { + if (offset != -1) { UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = UserConfig.getInstance(currentAccount).migrateOffsetId; UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = UserConfig.getInstance(currentAccount).migrateOffsetDate; UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = UserConfig.getInstance(currentAccount).migrateOffsetUserId; @@ -4248,413 +3878,414 @@ public class MessagesController implements NotificationCenter.NotificationCenter FileLog.d("migrate stop due to reached loaded dialogs " + LocaleController.getInstance().formatterStats.format((long) date * 1000)); } } - } - cursor.dispose(); - - UserConfig.getInstance(currentAccount).migrateOffsetDate = lastMessage.date; - if (lastMessage.to_id.channel_id != 0) { - UserConfig.getInstance(currentAccount).migrateOffsetChannelId = lastMessage.to_id.channel_id; - UserConfig.getInstance(currentAccount).migrateOffsetChatId = 0; - UserConfig.getInstance(currentAccount).migrateOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).migrateOffsetChannelId) { - UserConfig.getInstance(currentAccount).migrateOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.chat_id != 0) { - UserConfig.getInstance(currentAccount).migrateOffsetChatId = lastMessage.to_id.chat_id; - UserConfig.getInstance(currentAccount).migrateOffsetChannelId = 0; - UserConfig.getInstance(currentAccount).migrateOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).migrateOffsetChatId) { - UserConfig.getInstance(currentAccount).migrateOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.user_id != 0) { - UserConfig.getInstance(currentAccount).migrateOffsetUserId = lastMessage.to_id.user_id; - UserConfig.getInstance(currentAccount).migrateOffsetChatId = 0; - UserConfig.getInstance(currentAccount).migrateOffsetChannelId = 0; - for (int a = 0; a < dialogsRes.users.size(); a++) { - TLRPC.User user = dialogsRes.users.get(a); - if (user.id == UserConfig.getInstance(currentAccount).migrateOffsetUserId) { - UserConfig.getInstance(currentAccount).migrateOffsetAccess = user.access_hash; - break; - } + dialogsRes.messages.remove(a); + a--; + long did = MessageObject.getDialogId(message); + TLRPC.TL_dialog dialog = dialogHashMap.get(did); + dialogHashMap.remove(did); + if (dialog != null) { + dialogsRes.dialogs.remove(dialog); } } - - processLoadedDialogs(dialogsRes, null, offsetId, 0, 0, false, true, false); - } catch (Exception e) { - FileLog.e(e); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - migratingDialogs = false; - } - }); + } + if (lastMessage != null && lastMessage.date < date && offset != -1) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = UserConfig.getInstance(currentAccount).migrateOffsetId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = UserConfig.getInstance(currentAccount).migrateOffsetDate; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = UserConfig.getInstance(currentAccount).migrateOffsetUserId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = UserConfig.getInstance(currentAccount).migrateOffsetChatId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = UserConfig.getInstance(currentAccount).migrateOffsetChannelId; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = UserConfig.getInstance(currentAccount).migrateOffsetAccess; + offsetId = -1; + if (BuildVars.LOGS_ENABLED) { + FileLog.d("migrate stop due to reached loaded dialogs " + LocaleController.getInstance().formatterStats.format((long) date * 1000)); + } } } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - migratingDialogs = false; + cursor.dispose(); + + UserConfig.getInstance(currentAccount).migrateOffsetDate = lastMessage.date; + if (lastMessage.to_id.channel_id != 0) { + UserConfig.getInstance(currentAccount).migrateOffsetChannelId = lastMessage.to_id.channel_id; + UserConfig.getInstance(currentAccount).migrateOffsetChatId = 0; + UserConfig.getInstance(currentAccount).migrateOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).migrateOffsetChannelId) { + UserConfig.getInstance(currentAccount).migrateOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.chat_id != 0) { + UserConfig.getInstance(currentAccount).migrateOffsetChatId = lastMessage.to_id.chat_id; + UserConfig.getInstance(currentAccount).migrateOffsetChannelId = 0; + UserConfig.getInstance(currentAccount).migrateOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).migrateOffsetChatId) { + UserConfig.getInstance(currentAccount).migrateOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.user_id != 0) { + UserConfig.getInstance(currentAccount).migrateOffsetUserId = lastMessage.to_id.user_id; + UserConfig.getInstance(currentAccount).migrateOffsetChatId = 0; + UserConfig.getInstance(currentAccount).migrateOffsetChannelId = 0; + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User user = dialogsRes.users.get(a); + if (user.id == UserConfig.getInstance(currentAccount).migrateOffsetUserId) { + UserConfig.getInstance(currentAccount).migrateOffsetAccess = user.access_hash; + break; + } + } } - }); - } + + processLoadedDialogs(dialogsRes, null, offsetId, 0, 0, false, true, false); + } catch (Exception e) { + FileLog.e(e); + AndroidUtilities.runOnUIThread(() -> migratingDialogs = false); + } + }); + } else { + AndroidUtilities.runOnUIThread(() -> migratingDialogs = false); } }); } public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, final ArrayList encChats, final int offset, final int count, final int loadType, final boolean resetEnd, final boolean migrate, final boolean fromCache) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (!firstGettingTask) { - getNewDeleteTask(null, 0); - firstGettingTask = true; - } + Utilities.stageQueue.postRunnable(() -> { + if (!firstGettingTask) { + getNewDeleteTask(null, 0); + firstGettingTask = true; + } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("loaded loadType " + loadType + " count " + dialogsRes.dialogs.size()); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("loaded loadType " + loadType + " count " + dialogsRes.dialogs.size()); + } + if (loadType == 1 && dialogsRes.dialogs.size() == 0) { + AndroidUtilities.runOnUIThread(() -> { + putUsers(dialogsRes.users, true); + loadingDialogs = false; + if (resetEnd) { + dialogsEndReached = false; + serverDialogsEndReached = false; + } else if (UserConfig.getInstance(currentAccount).dialogsLoadOffsetId == Integer.MAX_VALUE) { + dialogsEndReached = true; + serverDialogsEndReached = true; + } else { + loadDialogs(0, count, false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); + return; + } + + final LongSparseArray new_dialogs_dict = new LongSparseArray<>(); + final LongSparseArray new_dialogMessage = new LongSparseArray<>(); + final SparseArray usersDict = new SparseArray<>(); + final SparseArray chatsDict = new SparseArray<>(); + + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User u = dialogsRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat c = dialogsRes.chats.get(a); + chatsDict.put(c.id, c); + } + if (loadType == 1) { + nextDialogsCacheOffset = offset + count; + } + + TLRPC.Message lastMessage = null; + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (lastMessage == null || message.date < lastMessage.date) { + lastMessage = message; } - if (loadType == 1 && dialogsRes.dialogs.size() == 0) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(dialogsRes.users, true); - loadingDialogs = false; - if (resetEnd) { - dialogsEndReached = false; - serverDialogsEndReached = false; - } else if (UserConfig.getInstance(currentAccount).dialogsLoadOffsetId == Integer.MAX_VALUE) { - dialogsEndReached = true; - serverDialogsEndReached = true; - } else { - loadDialogs(0, count, false); + if (message.to_id.channel_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); + if (chat != null && chat.left && (proxyDialogId == 0 || proxyDialogId != -chat.id)) { + continue; + } + if (chat != null && chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } else if (message.to_id.chat_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); + new_dialogMessage.put(messageObject.getDialogId(), messageObject); + } + + if (!fromCache && !migrate && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && loadType == 0) { + if (lastMessage != null && lastMessage.id != UserConfig.getInstance(currentAccount).dialogsLoadOffsetId) { + UserConfig.getInstance(currentAccount).totalDialogsLoadCount += dialogsRes.dialogs.size(); + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = lastMessage.id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = lastMessage.date; + if (lastMessage.to_id.channel_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = lastMessage.to_id.channel_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; + break; } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } - }); - return; + } else if (lastMessage.to_id.chat_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = lastMessage.to_id.chat_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.user_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = lastMessage.to_id.user_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User user = dialogsRes.users.get(a); + if (user.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = user.access_hash; + break; + } + } + } + } else { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; + } + UserConfig.getInstance(currentAccount).saveConfig(false); + } + + final ArrayList dialogsToReload = new ArrayList<>(); + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.TL_dialog d = dialogsRes.dialogs.get(a); + if (d.id == 0 && d.peer != null) { + if (d.peer.user_id != 0) { + d.id = d.peer.user_id; + } else if (d.peer.chat_id != 0) { + d.id = -d.peer.chat_id; + } else if (d.peer.channel_id != 0) { + d.id = -d.peer.channel_id; + } + } + if (d.id == 0) { + continue; + } + if (proxyDialogId != 0 && proxyDialogId == d.id) { + proxyDialog = d; + } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + boolean allowCheck = true; + if (DialogObject.isChannel(d)) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null) { + if (!chat.megagroup) { + allowCheck = false; + } + if (chat.left && (proxyDialogId == 0 || proxyDialogId != d.id)) { + continue; + } + } + channelsPts.put(-(int) d.id, d.pts); + } else if ((int) d.id < 0) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + new_dialogs_dict.put(d.id, d); + + if (allowCheck && loadType == 1 && (d.read_outbox_max_id == 0 || d.read_inbox_max_id == 0) && d.top_message != 0) { + dialogsToReload.add(d); } - final LongSparseArray new_dialogs_dict = new LongSparseArray<>(); - final LongSparseArray new_dialogMessage = new LongSparseArray<>(); - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); + Integer value = dialogs_read_inbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); - for (int a = 0; a < dialogsRes.users.size(); a++) { - TLRPC.User u = dialogsRes.users.get(a); - usersDict.put(u.id, u); - } - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat c = dialogsRes.chats.get(a); - chatsDict.put(c.id, c); - } - if (loadType == 1) { - nextDialogsCacheOffset = offset + count; + value = dialogs_read_outbox_max.get(d.id); + if (value == null) { + value = 0; } + dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); + } + + if (loadType != 1) { + ImageLoader.saveMessagesThumbs(dialogsRes.messages); - TLRPC.Message lastMessage = null; for (int a = 0; a < dialogsRes.messages.size(); a++) { TLRPC.Message message = dialogsRes.messages.get(a); - if (lastMessage == null || message.date < lastMessage.date) { - lastMessage = message; - } - if (message.to_id.channel_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); - if (chat != null && chat.left && (proxyDialogId == 0 || proxyDialogId != -chat.id)) { - continue; - } - if (chat != null && chat.megagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } else if (message.to_id.chat_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); - if (chat != null && chat.migrated_to != null) { - continue; + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + message.flags |= 64; } } - MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); - new_dialogMessage.put(messageObject.getDialogId(), messageObject); - } - if (!fromCache && !migrate && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && loadType == 0) { - if (lastMessage != null && lastMessage.id != UserConfig.getInstance(currentAccount).dialogsLoadOffsetId) { - UserConfig.getInstance(currentAccount).totalDialogsLoadCount += dialogsRes.dialogs.size(); - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = lastMessage.id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = lastMessage.date; - if (lastMessage.to_id.channel_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = lastMessage.to_id.channel_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.chat_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = lastMessage.to_id.chat_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.user_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = lastMessage.to_id.user_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; - for (int a = 0; a < dialogsRes.users.size(); a++) { - TLRPC.User user = dialogsRes.users.get(a); - if (user.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = user.access_hash; - break; - } + if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } else { + ConcurrentHashMap read_max = message.out ? dialogs_read_outbox_max : dialogs_read_inbox_max; + Integer value = read_max.get(message.dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); + read_max.put(message.dialog_id, value); + } + message.unread = value < message.id; + } + } + MessagesStorage.getInstance(currentAccount).putDialogs(dialogsRes, 0); + } + if (loadType == 2) { + TLRPC.Chat chat = dialogsRes.chats.get(0); + getChannelDifference(chat.id); + checkChannelInviter(chat.id); + } + + AndroidUtilities.runOnUIThread(() -> { + if (loadType != 1) { + applyDialogsNotificationsSettings(dialogsRes.dialogs); + if (!UserConfig.getInstance(currentAccount).draftsLoaded) { + DataQuery.getInstance(currentAccount).loadDrafts(); + } + } + putUsers(dialogsRes.users, loadType == 1); + putChats(dialogsRes.chats, loadType == 1); + if (encChats != null) { + for (int a = 0; a < encChats.size(); a++) { + TLRPC.EncryptedChat encryptedChat = encChats.get(a); + if (encryptedChat instanceof TLRPC.TL_encryptedChat && AndroidUtilities.getMyLayerVersion(encryptedChat.layer) < SecretChatHelper.CURRENT_SECRET_CHAT_LAYER) { + SecretChatHelper.getInstance(currentAccount).sendNotifyLayerMessage(encryptedChat, null); + } + putEncryptedChat(encryptedChat, true); + } + } + if (!migrate) { + loadingDialogs = false; + } + boolean added = false; + + int lastDialogDate = migrate && !dialogs.isEmpty() ? dialogs.get(dialogs.size() - 1).last_message_date : 0; + for (int a = 0; a < new_dialogs_dict.size(); a++) { + long key = new_dialogs_dict.keyAt(a); + TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); + if (migrate && lastDialogDate != 0 && value.last_message_date < lastDialogDate) { + continue; + } + TLRPC.TL_dialog currentDialog = dialogs_dict.get(key); + if (loadType != 1 && value.draft instanceof TLRPC.TL_draftMessage) { + DataQuery.getInstance(currentAccount).saveDraft(value.id, value.draft, null, false); + } + if (currentDialog == null) { + added = true; + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); } } } else { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; - } - UserConfig.getInstance(currentAccount).saveConfig(false); - } - - final ArrayList dialogsToReload = new ArrayList<>(); - for (int a = 0; a < dialogsRes.dialogs.size(); a++) { - TLRPC.TL_dialog d = dialogsRes.dialogs.get(a); - if (d.id == 0 && d.peer != null) { - if (d.peer.user_id != 0) { - d.id = d.peer.user_id; - } else if (d.peer.chat_id != 0) { - d.id = -d.peer.chat_id; - } else if (d.peer.channel_id != 0) { - d.id = -d.peer.channel_id; - } - } - if (d.id == 0) { - continue; - } - if (proxyDialogId != 0 && proxyDialogId == d.id) { - proxyDialog = d; - } - if (d.last_message_date == 0) { - MessageObject mess = new_dialogMessage.get(d.id); - if (mess != null) { - d.last_message_date = mess.messageOwner.date; - } - } - boolean allowCheck = true; - if (DialogObject.isChannel(d)) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null) { - if (!chat.megagroup) { - allowCheck = false; - } - if (chat.left && (proxyDialogId == 0 || proxyDialogId != d.id)) { - continue; - } - } - channelsPts.put(-(int) d.id, d.pts); - } else if ((int) d.id < 0) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.migrated_to != null) { - continue; - } - } - new_dialogs_dict.put(d.id, d); - - if (allowCheck && loadType == 1 && (d.read_outbox_max_id == 0 || d.read_inbox_max_id == 0) && d.top_message != 0) { - dialogsToReload.add(d); - } - - Integer value = dialogs_read_inbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); - - value = dialogs_read_outbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); - } - - if (loadType != 1) { - ImageLoader.saveMessagesThumbs(dialogsRes.messages); - - for (int a = 0; a < dialogsRes.messages.size(); a++) { - TLRPC.Message message = dialogsRes.messages.get(a); - if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { - TLRPC.User user = usersDict.get(message.action.user_id); - if (user != null && user.bot) { - message.reply_markup = new TLRPC.TL_replyKeyboardHide(); - message.flags |= 64; - } - } - - if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { - message.unread = false; - message.media_unread = false; - } else { - ConcurrentHashMap read_max = message.out ? dialogs_read_outbox_max : dialogs_read_inbox_max; - Integer value = read_max.get(message.dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); - read_max.put(message.dialog_id, value); - } - message.unread = value < message.id; - } - } - MessagesStorage.getInstance(currentAccount).putDialogs(dialogsRes, 0); - } - if (loadType == 2) { - TLRPC.Chat chat = dialogsRes.chats.get(0); - getChannelDifference(chat.id); - checkChannelInviter(chat.id); - } - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { if (loadType != 1) { - applyDialogsNotificationsSettings(dialogsRes.dialogs); - if (!UserConfig.getInstance(currentAccount).draftsLoaded) { - DataQuery.getInstance(currentAccount).loadDrafts(); - } + currentDialog.notify_settings = value.notify_settings; } - putUsers(dialogsRes.users, loadType == 1); - putChats(dialogsRes.chats, loadType == 1); - if (encChats != null) { - for (int a = 0; a < encChats.size(); a++) { - TLRPC.EncryptedChat encryptedChat = encChats.get(a); - if (encryptedChat instanceof TLRPC.TL_encryptedChat && AndroidUtilities.getMyLayerVersion(encryptedChat.layer) < SecretChatHelper.CURRENT_SECRET_CHAT_LAYER) { - SecretChatHelper.getInstance(currentAccount).sendNotifyLayerMessage(encryptedChat, null); - } - putEncryptedChat(encryptedChat, true); - } - } - if (!migrate) { - loadingDialogs = false; - } - boolean added = false; - - int lastDialogDate = migrate && !dialogs.isEmpty() ? dialogs.get(dialogs.size() - 1).last_message_date : 0; - for (int a = 0; a < new_dialogs_dict.size(); a++) { - long key = new_dialogs_dict.keyAt(a); - TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); - if (migrate && lastDialogDate != 0 && value.last_message_date < lastDialogDate) { - continue; - } - TLRPC.TL_dialog currentDialog = dialogs_dict.get(key); - if (loadType != 1 && value.draft instanceof TLRPC.TL_draftMessage) { - DataQuery.getInstance(currentAccount).saveDraft(value.id, value.draft, null, false); - } - if (currentDialog == null) { - added = true; + currentDialog.pinned = value.pinned; + currentDialog.pinnedNum = value.pinnedNum; + MessageObject oldMsg = dialogMessage.get(key); + if (oldMsg != null && oldMsg.deleted || oldMsg == null || currentDialog.top_message > 0) { + if (value.top_message >= currentDialog.top_message) { dialogs_dict.put(key, value); MessageObject messageObject = new_dialogMessage.get(value.id); dialogMessage.put(key, messageObject); if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { + if (messageObject != null && messageObject.messageOwner.random_id != 0) { dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); } } - } else { - if (loadType != 1) { - currentDialog.notify_settings = value.notify_settings; - } - currentDialog.pinned = value.pinned; - currentDialog.pinnedNum = value.pinnedNum; - MessageObject oldMsg = dialogMessage.get(key); - if (oldMsg != null && oldMsg.deleted || oldMsg == null || currentDialog.top_message > 0) { - if (value.top_message >= currentDialog.top_message) { - dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject != null && messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } - if (oldMsg != null) { - dialogMessagesByIds.remove(oldMsg.getId()); - if (oldMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); - } - } - } - } else { - MessageObject newMsg = new_dialogMessage.get(value.id); - if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { - dialogs_dict.put(key, value); - dialogMessage.put(key, newMsg); - if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(newMsg.getId(), newMsg); - if (newMsg != null && newMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); - } - } - dialogMessagesByIds.remove(oldMsg.getId()); - if (oldMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); - } + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } } - } - - dialogs.clear(); - for (int a = 0, size = dialogs_dict.size(); a < size; a++) { - dialogs.add(dialogs_dict.valueAt(a)); - } - sortDialogs(migrate ? chatsDict : null); - - if (loadType != 2) { - if (!migrate) { - dialogsEndReached = (dialogsRes.dialogs.size() == 0 || dialogsRes.dialogs.size() != count) && loadType == 0; - if (!fromCache) { - serverDialogsEndReached = (dialogsRes.dialogs.size() == 0 || dialogsRes.dialogs.size() != count) && loadType == 0; - } - } - } - if (!fromCache && !migrate && UserConfig.getInstance(currentAccount).totalDialogsLoadCount < 400 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != Integer.MAX_VALUE) { - loadDialogs(0, 100, false); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - - if (migrate) { - UserConfig.getInstance(currentAccount).migrateOffsetId = offset; - UserConfig.getInstance(currentAccount).saveConfig(false); - migratingDialogs = false; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); } else { - generateUpdateMessage(); - if (!added && loadType == 1) { - loadDialogs(0, count, false); + MessageObject newMsg = new_dialogMessage.get(value.id); + if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg != null && newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } } } - migrateDialogs(UserConfig.getInstance(currentAccount).migrateOffsetId, UserConfig.getInstance(currentAccount).migrateOffsetDate, UserConfig.getInstance(currentAccount).migrateOffsetUserId, UserConfig.getInstance(currentAccount).migrateOffsetChatId, UserConfig.getInstance(currentAccount).migrateOffsetChannelId, UserConfig.getInstance(currentAccount).migrateOffsetAccess); - if (!dialogsToReload.isEmpty()) { - reloadDialogsReadValue(dialogsToReload, 0); - } - loadUnreadDialogs(); } - }); - } + } + + dialogs.clear(); + for (int a = 0, size = dialogs_dict.size(); a < size; a++) { + dialogs.add(dialogs_dict.valueAt(a)); + } + sortDialogs(migrate ? chatsDict : null); + + if (loadType != 2) { + if (!migrate) { + dialogsEndReached = (dialogsRes.dialogs.size() == 0 || dialogsRes.dialogs.size() != count) && loadType == 0; + if (!fromCache) { + serverDialogsEndReached = (dialogsRes.dialogs.size() == 0 || dialogsRes.dialogs.size() != count) && loadType == 0; + } + } + } + if (!fromCache && !migrate && UserConfig.getInstance(currentAccount).totalDialogsLoadCount < 400 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != -1 && UserConfig.getInstance(currentAccount).dialogsLoadOffsetId != Integer.MAX_VALUE) { + loadDialogs(0, 100, false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + + if (migrate) { + UserConfig.getInstance(currentAccount).migrateOffsetId = offset; + UserConfig.getInstance(currentAccount).saveConfig(false); + migratingDialogs = false; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); + } else { + generateUpdateMessage(); + if (!added && loadType == 1) { + loadDialogs(0, count, false); + } + } + migrateDialogs(UserConfig.getInstance(currentAccount).migrateOffsetId, UserConfig.getInstance(currentAccount).migrateOffsetDate, UserConfig.getInstance(currentAccount).migrateOffsetUserId, UserConfig.getInstance(currentAccount).migrateOffsetChatId, UserConfig.getInstance(currentAccount).migrateOffsetChannelId, UserConfig.getInstance(currentAccount).migrateOffsetAccess); + if (!dialogsToReload.isEmpty()) { + reloadDialogsReadValue(dialogsToReload, 0); + } + loadUnreadDialogs(); + }); }); } @@ -4766,74 +4397,60 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void reloadMentionsCountForChannels(final ArrayList arrayList) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < arrayList.size(); a++) { - final long dialog_id = -arrayList.get(a); - TLRPC.TL_messages_getUnreadMentions req = new TLRPC.TL_messages_getUnreadMentions(); - req.peer = getInputPeer((int) dialog_id); - req.limit = 1; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - if (res != null) { - int newCount; - if (res.count != 0) { - newCount = res.count; - } else { - newCount = res.messages.size(); - } - MessagesStorage.getInstance(currentAccount).resetMentionsCount(dialog_id, newCount); - } - } - }); + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < arrayList.size(); a++) { + final long dialog_id = -arrayList.get(a); + TLRPC.TL_messages_getUnreadMentions req = new TLRPC.TL_messages_getUnreadMentions(); + req.peer = getInputPeer((int) dialog_id); + req.limit = 1; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (res != null) { + int newCount; + if (res.count != 0) { + newCount = res.count; + } else { + newCount = res.messages.size(); } - }); - } + MessagesStorage.getInstance(currentAccount).resetMentionsCount(dialog_id, newCount); + } + })); } }); } public void processDialogsUpdateRead(final LongSparseArray dialogsToUpdate, final LongSparseArray dialogsMentionsToUpdate) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (dialogsToUpdate != null) { - for (int a = 0; a < dialogsToUpdate.size(); a++) { - long dialogId = dialogsToUpdate.keyAt(a); - TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialogId); - if (currentDialog != null) { - int prevCount = currentDialog.unread_count; - currentDialog.unread_count = dialogsToUpdate.valueAt(a); - if (prevCount != 0 && currentDialog.unread_count == 0 && !isDialogMuted(dialogId)) { - unreadUnmutedDialogs--; - } else if (prevCount == 0 && !currentDialog.unread_mark && currentDialog.unread_count != 0 && !isDialogMuted(dialogId)) { - unreadUnmutedDialogs++; - } + AndroidUtilities.runOnUIThread(() -> { + if (dialogsToUpdate != null) { + for (int a = 0; a < dialogsToUpdate.size(); a++) { + long dialogId = dialogsToUpdate.keyAt(a); + TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialogId); + if (currentDialog != null) { + int prevCount = currentDialog.unread_count; + currentDialog.unread_count = dialogsToUpdate.valueAt(a); + if (prevCount != 0 && currentDialog.unread_count == 0 && !isDialogMuted(dialogId)) { + unreadUnmutedDialogs--; + } else if (prevCount == 0 && !currentDialog.unread_mark && currentDialog.unread_count != 0 && !isDialogMuted(dialogId)) { + unreadUnmutedDialogs++; } } } - if (dialogsMentionsToUpdate != null) { - for (int a = 0; a < dialogsMentionsToUpdate.size(); a++) { - long dialogId = dialogsMentionsToUpdate.keyAt(a); - TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialogId); - if (currentDialog != null) { - currentDialog.unread_mentions_count = dialogsMentionsToUpdate.valueAt(a); - if (createdDialogMainThreadIds.contains(currentDialog.id)) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, currentDialog.unread_mentions_count); - } + } + if (dialogsMentionsToUpdate != null) { + for (int a = 0; a < dialogsMentionsToUpdate.size(); a++) { + long dialogId = dialogsMentionsToUpdate.keyAt(a); + TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialogId); + if (currentDialog != null) { + currentDialog.unread_mentions_count = dialogsMentionsToUpdate.valueAt(a); + if (createdDialogMainThreadIds.contains(currentDialog.id)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, currentDialog.unread_mentions_count); } } } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); - if (dialogsToUpdate != null) { - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); - } + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); + if (dialogsToUpdate != null) { + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); } }); } @@ -4878,155 +4495,160 @@ public class MessagesController implements NotificationCenter.NotificationCenter newTaskId = taskId; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - if (!res.messages.isEmpty()) { - TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); - TLRPC.Message newMessage = res.messages.get(0); - TLRPC.TL_dialog newDialog = new TLRPC.TL_dialog(); - newDialog.flags = dialog.flags; - newDialog.top_message = newMessage.id; - newDialog.last_message_date = newMessage.date; - newDialog.notify_settings = dialog.notify_settings; - newDialog.pts = dialog.pts; - newDialog.unread_count = dialog.unread_count; - newDialog.unread_mark = dialog.unread_mark; - newDialog.unread_mentions_count = dialog.unread_mentions_count; - newDialog.read_inbox_max_id = dialog.read_inbox_max_id; - newDialog.read_outbox_max_id = dialog.read_outbox_max_id; - newDialog.pinned = dialog.pinned; - newDialog.pinnedNum = dialog.pinnedNum; - newMessage.dialog_id = newDialog.id = dialog.id; - dialogs.users.addAll(res.users); - dialogs.chats.addAll(res.chats); - dialogs.dialogs.add(newDialog); - dialogs.messages.addAll(res.messages); - dialogs.count = 1; - processDialogsUpdate(dialogs, null); - MessagesStorage.getInstance(currentAccount).putMessages(res.messages, true, true, false, DownloadController.getInstance(currentAccount).getAutodownloadMask(), true); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialog.id); - if (currentDialog != null && currentDialog.top_message == 0) { - deleteDialog(dialog.id, 3); - } - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (!res.messages.isEmpty()) { + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + TLRPC.Message newMessage = res.messages.get(0); + TLRPC.TL_dialog newDialog = new TLRPC.TL_dialog(); + newDialog.flags = dialog.flags; + newDialog.top_message = newMessage.id; + newDialog.last_message_date = newMessage.date; + newDialog.notify_settings = dialog.notify_settings; + newDialog.pts = dialog.pts; + newDialog.unread_count = dialog.unread_count; + newDialog.unread_mark = dialog.unread_mark; + newDialog.unread_mentions_count = dialog.unread_mentions_count; + newDialog.read_inbox_max_id = dialog.read_inbox_max_id; + newDialog.read_outbox_max_id = dialog.read_outbox_max_id; + newDialog.pinned = dialog.pinned; + newDialog.pinnedNum = dialog.pinnedNum; + newMessage.dialog_id = newDialog.id = dialog.id; + dialogs.users.addAll(res.users); + dialogs.chats.addAll(res.chats); + dialogs.dialogs.add(newDialog); + dialogs.messages.addAll(res.messages); + dialogs.count = 1; + processDialogsUpdate(dialogs, null); + MessagesStorage.getInstance(currentAccount).putMessages(res.messages, true, true, false, DownloadController.getInstance(currentAccount).getAutodownloadMask(), true); + } else { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_dialog currentDialog = dialogs_dict.get(dialog.id); + if (currentDialog != null && currentDialog.top_message == 0) { + deleteDialog(dialog.id, 3); + } + }); } - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkingLastMessagesDialogs.delete(lower_id); - } - }); } + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); + } + AndroidUtilities.runOnUIThread(() -> checkingLastMessagesDialogs.delete(lower_id)); }); } public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - final LongSparseArray new_dialogs_dict = new LongSparseArray<>(); - final LongSparseArray new_dialogMessage = new LongSparseArray<>(); - final SparseArray usersDict = new SparseArray<>(dialogsRes.users.size()); - final SparseArray chatsDict = new SparseArray<>(dialogsRes.chats.size()); - final LongSparseArray dialogsToUpdate = new LongSparseArray<>(); + Utilities.stageQueue.postRunnable(() -> { + final LongSparseArray new_dialogs_dict = new LongSparseArray<>(); + final LongSparseArray new_dialogMessage = new LongSparseArray<>(); + final SparseArray usersDict = new SparseArray<>(dialogsRes.users.size()); + final SparseArray chatsDict = new SparseArray<>(dialogsRes.chats.size()); + final LongSparseArray dialogsToUpdate = new LongSparseArray<>(); - for (int a = 0; a < dialogsRes.users.size(); a++) { - TLRPC.User u = dialogsRes.users.get(a); - usersDict.put(u.id, u); - } - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat c = dialogsRes.chats.get(a); - chatsDict.put(c.id, c); - } + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User u = dialogsRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat c = dialogsRes.chats.get(a); + chatsDict.put(c.id, c); + } - for (int a = 0; a < dialogsRes.messages.size(); a++) { - TLRPC.Message message = dialogsRes.messages.get(a); - if (proxyDialogId == 0 || proxyDialogId != message.dialog_id) { - if (message.to_id.channel_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); - if (chat != null && chat.left) { - continue; - } - } else if (message.to_id.chat_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); - if (chat != null && chat.migrated_to != null) { - continue; - } + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (proxyDialogId == 0 || proxyDialogId != message.dialog_id) { + if (message.to_id.channel_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); + if (chat != null && chat.left) { + continue; + } + } else if (message.to_id.chat_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); + if (chat != null && chat.migrated_to != null) { + continue; } } - MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); - new_dialogMessage.put(messageObject.getDialogId(), messageObject); } - for (int a = 0; a < dialogsRes.dialogs.size(); a++) { - TLRPC.TL_dialog d = dialogsRes.dialogs.get(a); - if (d.id == 0) { - if (d.peer.user_id != 0) { - d.id = d.peer.user_id; - } else if (d.peer.chat_id != 0) { - d.id = -d.peer.chat_id; - } else if (d.peer.channel_id != 0) { - d.id = -d.peer.channel_id; + MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); + new_dialogMessage.put(messageObject.getDialogId(), messageObject); + } + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.TL_dialog d = dialogsRes.dialogs.get(a); + if (d.id == 0) { + if (d.peer.user_id != 0) { + d.id = d.peer.user_id; + } else if (d.peer.chat_id != 0) { + d.id = -d.peer.chat_id; + } else if (d.peer.channel_id != 0) { + d.id = -d.peer.channel_id; + } + } + if (proxyDialogId == 0 || proxyDialogId != d.id) { + if (DialogObject.isChannel(d)) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.left) { + continue; + } + } else if ((int) d.id < 0) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + continue; } } - if (proxyDialogId == 0 || proxyDialogId != d.id) { - if (DialogObject.isChannel(d)) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.left) { - continue; - } - } else if ((int) d.id < 0) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.migrated_to != null) { - continue; + } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + new_dialogs_dict.put(d.id, d); + dialogsToUpdate.put(d.id, d.unread_count); + + Integer value = dialogs_read_inbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); + + value = dialogs_read_outbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); + } + + AndroidUtilities.runOnUIThread(() -> { + putUsers(dialogsRes.users, true); + putChats(dialogsRes.chats, true); + + for (int a = 0; a < new_dialogs_dict.size(); a++) { + long key = new_dialogs_dict.keyAt(a); + TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); + TLRPC.TL_dialog currentDialog = dialogs_dict.get(key); + if (currentDialog == null) { + nextDialogsCacheOffset++; + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); } } - } - if (d.last_message_date == 0) { - MessageObject mess = new_dialogMessage.get(d.id); - if (mess != null) { - d.last_message_date = mess.messageOwner.date; + } else { + currentDialog.unread_count = value.unread_count; + if (currentDialog.unread_mentions_count != value.unread_mentions_count) { + currentDialog.unread_mentions_count = value.unread_mentions_count; + if (createdDialogMainThreadIds.contains(currentDialog.id)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, currentDialog.unread_mentions_count); + } } - } - new_dialogs_dict.put(d.id, d); - dialogsToUpdate.put(d.id, d.unread_count); - - Integer value = dialogs_read_inbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); - - value = dialogs_read_outbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); - } - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(dialogsRes.users, true); - putChats(dialogsRes.chats, true); - - for (int a = 0; a < new_dialogs_dict.size(); a++) { - long key = new_dialogs_dict.keyAt(a); - TLRPC.TL_dialog value = new_dialogs_dict.valueAt(a); - TLRPC.TL_dialog currentDialog = dialogs_dict.get(key); - if (currentDialog == null) { - nextDialogsCacheOffset++; + MessageObject oldMsg = dialogMessage.get(key); + if (oldMsg == null || currentDialog.top_message > 0) { + if (oldMsg != null && oldMsg.deleted || value.top_message > currentDialog.top_message) { dialogs_dict.put(key, value); MessageObject messageObject = new_dialogMessage.get(value.id); dialogMessage.put(key, messageObject); @@ -5036,89 +4658,64 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); } } - } else { - currentDialog.unread_count = value.unread_count; - if (currentDialog.unread_mentions_count != value.unread_mentions_count) { - currentDialog.unread_mentions_count = value.unread_mentions_count; - if (createdDialogMainThreadIds.contains(currentDialog.id)) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, currentDialog.unread_mentions_count); + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } - MessageObject oldMsg = dialogMessage.get(key); - if (oldMsg == null || currentDialog.top_message > 0) { - if (oldMsg != null && oldMsg.deleted || value.top_message > currentDialog.top_message) { - dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } - if (oldMsg != null) { - dialogMessagesByIds.remove(oldMsg.getId()); - if (oldMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); - } - } - if (messageObject == null) { - checkLastDialogMessage(value, null, 0); - } - } - } else { - MessageObject newMsg = new_dialogMessage.get(value.id); - if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { - dialogs_dict.put(key, value); - dialogMessage.put(key, newMsg); - if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(newMsg.getId(), newMsg); - if (newMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); - } - } - dialogMessagesByIds.remove(oldMsg.getId()); - if (oldMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); - } + if (messageObject == null) { + checkLastDialogMessage(value, null, 0); + } + } + } else { + MessageObject newMsg = new_dialogMessage.get(value.id); + if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); } } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } } } - - dialogs.clear(); - for (int a = 0, size = dialogs_dict.size(); a < size; a++) { - dialogs.add(dialogs_dict.valueAt(a)); - } - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); } - }); - } + } + + dialogs.clear(); + for (int a = 0, size = dialogs_dict.size(); a < size; a++) { + dialogs.add(dialogs_dict.valueAt(a)); + } + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + }); }); } public void addToViewsQueue(final TLRPC.Message message) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - int peer; - if (message.to_id.channel_id != 0) { - peer = -message.to_id.channel_id; - } else if (message.to_id.chat_id != 0) { - peer = -message.to_id.chat_id; - } else { - peer = message.to_id.user_id; - } - ArrayList ids = channelViewsToSend.get(peer); - if (ids == null) { - ids = new ArrayList<>(); - channelViewsToSend.put(peer, ids); - } - if (!ids.contains(message.id)) { - ids.add(message.id); - } + Utilities.stageQueue.postRunnable(() -> { + int peer; + if (message.to_id.channel_id != 0) { + peer = -message.to_id.channel_id; + } else if (message.to_id.chat_id != 0) { + peer = -message.to_id.chat_id; + } else { + peer = message.to_id.user_id; + } + ArrayList ids = channelViewsToSend.get(peer); + if (ids == null) { + ids = new ArrayList<>(); + channelViewsToSend.put(peer, ids); + } + if (!ids.contains(message.id)) { + ids.add(message.id); } }); } @@ -5145,22 +4742,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter return; } req.id.add(messageObject.getId()); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } else { TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); req.id.add(messageObject.getId()); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); } }); } @@ -5176,22 +4767,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter return; } req.id.add(mid); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } else { TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); req.id.add(mid); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); } }); } @@ -5207,22 +4792,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_readMessageContents req = new TLRPC.TL_channels_readMessageContents(); req.channel = getInputChannel(channelId); req.id.add(mid); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } else { TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); req.id.add(mid); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); } }); } @@ -5268,14 +4847,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter request.max_id = task.maxId; req = request; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - if (response instanceof TLRPC.TL_messages_affectedMessages) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + if (response instanceof TLRPC.TL_messages_affectedMessages) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); } } }); @@ -5287,11 +4863,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer.chat_id = chat.id; req.peer.access_hash = chat.access_hash; req.max_date = task.maxDate; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -5313,17 +4886,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void markDialogAsReadNow(final long dialogId) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ReadTask currentReadTask = readTasksMap.get(dialogId); - if (currentReadTask == null) { - return; - } - completeReadTask(currentReadTask); - readTasks.remove(currentReadTask); - readTasksMap.remove(dialogId); + Utilities.stageQueue.postRunnable(() -> { + ReadTask currentReadTask = readTasksMap.get(dialogId); + if (currentReadTask == null) { + return; } + completeReadTask(currentReadTask); + readTasks.remove(currentReadTask); + readTasksMap.remove(dialogId); }); } @@ -5334,11 +4904,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter MessagesStorage.getInstance(currentAccount).resetMentionsCount(dialogId, 0); TLRPC.TL_messages_readMentions req = new TLRPC.TL_messages_readMentions(); req.peer = MessagesController.getInstance(currentAccount).getInputPeer((int) dialogId); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -5369,47 +4936,39 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogs_read_inbox_max.put(dialogId, Math.max(value, maxPositiveId)); MessagesStorage.getInstance(currentAccount).processPendingRead(dialogId, maxMessageId, minMessageId, maxDate, isChannel); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.TL_dialog dialog = dialogs_dict.get(dialogId); - if (dialog != null) { - int prevCount = dialog.unread_count; - if (countDiff == 0 || maxPositiveId >= dialog.top_message) { - dialog.unread_count = 0; - } else { - dialog.unread_count = Math.max(dialog.unread_count - countDiff, 0); - if (maxPositiveId != Integer.MIN_VALUE && dialog.unread_count > dialog.top_message - maxPositiveId) { - dialog.unread_count = dialog.top_message - maxPositiveId; - } - } - if ((prevCount != 0 || dialog.unread_mark) && dialog.unread_count == 0 && !isDialogMuted(dialogId)) { - unreadUnmutedDialogs--; - } - if (dialog.unread_mark) { - dialog.unread_mark = false; - MessagesStorage.getInstance(currentAccount).setDialogUnread(dialog.id, false); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); - } - if (!popup) { - NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, 0, maxPositiveId, false); - LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); - dialogsToUpdate.put(dialogId, 0); - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); - } else { - NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, 0, maxPositiveId, true); - LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); - dialogsToUpdate.put(dialogId, -1); - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_dialog dialog = dialogs_dict.get(dialogId); + if (dialog != null) { + int prevCount = dialog.unread_count; + if (countDiff == 0 || maxPositiveId >= dialog.top_message) { + dialog.unread_count = 0; + } else { + dialog.unread_count = Math.max(dialog.unread_count - countDiff, 0); + if (maxPositiveId != Integer.MIN_VALUE && dialog.unread_count > dialog.top_message - maxPositiveId) { + dialog.unread_count = dialog.top_message - maxPositiveId; } - }); + } + if ((prevCount != 0 || dialog.unread_mark) && dialog.unread_count == 0 && !isDialogMuted(dialogId)) { + unreadUnmutedDialogs--; + } + if (dialog.unread_mark) { + dialog.unread_mark = false; + MessagesStorage.getInstance(currentAccount).setDialogUnread(dialog.id, false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); } - }); + if (!popup) { + NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, 0, maxPositiveId, false); + LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); + dialogsToUpdate.put(dialogId, 0); + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + } else { + NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, 0, maxPositiveId, true); + LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); + dialogsToUpdate.put(dialogId, -1); + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + } + })); createReadTask = maxPositiveId != Integer.MAX_VALUE; } else { @@ -5420,40 +4979,32 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.EncryptedChat chat = getEncryptedChat(high_id); MessagesStorage.getInstance(currentAccount).processPendingRead(dialogId, maxPositiveId, maxNegativeId, maxDate, false); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, maxDate, 0, popup); - TLRPC.TL_dialog dialog = dialogs_dict.get(dialogId); - if (dialog != null) { - int prevCount = dialog.unread_count; - if (countDiff == 0 || maxNegativeId <= dialog.top_message) { - dialog.unread_count = 0; - } else { - dialog.unread_count = Math.max(dialog.unread_count - countDiff, 0); - if (maxNegativeId != Integer.MAX_VALUE && dialog.unread_count > maxNegativeId - dialog.top_message) { - dialog.unread_count = maxNegativeId - dialog.top_message; - } - } - if ((prevCount != 0 || dialog.unread_mark) && dialog.unread_count == 0 && !isDialogMuted(dialogId)) { - unreadUnmutedDialogs--; - } - if (dialog.unread_mark) { - dialog.unread_mark = false; - MessagesStorage.getInstance(currentAccount).setDialogUnread(dialog.id, false); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); - } - LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); - dialogsToUpdate.put(dialogId, 0); - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + NotificationsController.getInstance(currentAccount).processReadMessages(null, dialogId, maxDate, 0, popup); + TLRPC.TL_dialog dialog = dialogs_dict.get(dialogId); + if (dialog != null) { + int prevCount = dialog.unread_count; + if (countDiff == 0 || maxNegativeId <= dialog.top_message) { + dialog.unread_count = 0; + } else { + dialog.unread_count = Math.max(dialog.unread_count - countDiff, 0); + if (maxNegativeId != Integer.MAX_VALUE && dialog.unread_count > maxNegativeId - dialog.top_message) { + dialog.unread_count = maxNegativeId - dialog.top_message; } - }); + } + if ((prevCount != 0 || dialog.unread_mark) && dialog.unread_count == 0 && !isDialogMuted(dialogId)) { + unreadUnmutedDialogs--; + } + if (dialog.unread_mark) { + dialog.unread_mark = false; + MessagesStorage.getInstance(currentAccount).setDialogUnread(dialog.id, false); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); } - }); + LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); + dialogsToUpdate.put(dialogId, 0); + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + })); if (chat != null && chat.ttl > 0) { int serverTime = Math.max(ConnectionsManager.getInstance(currentAccount).getCurrentTime(), maxDate); @@ -5462,25 +5013,22 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (createReadTask) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ReadTask currentReadTask = readTasksMap.get(dialogId); - if (currentReadTask == null) { - currentReadTask = new ReadTask(); - currentReadTask.dialogId = dialogId; - currentReadTask.sendRequestTime = SystemClock.elapsedRealtime() + 5000; - if (!readNow) { - readTasksMap.put(dialogId, currentReadTask); - readTasks.add(currentReadTask); - } - } - currentReadTask.maxDate = maxDate; - currentReadTask.maxId = maxPositiveId; - if (readNow) { - completeReadTask(currentReadTask); + Utilities.stageQueue.postRunnable(() -> { + ReadTask currentReadTask = readTasksMap.get(dialogId); + if (currentReadTask == null) { + currentReadTask = new ReadTask(); + currentReadTask.dialogId = dialogId; + currentReadTask.sendRequestTime = SystemClock.elapsedRealtime() + 5000; + if (!readNow) { + readTasksMap.put(dialogId, currentReadTask); + readTasks.add(currentReadTask); } } + currentReadTask.maxDate = maxDate; + currentReadTask.maxId = maxPositiveId; + if (readNow) { + completeReadTask(currentReadTask); + } }); } } @@ -5552,34 +5100,25 @@ public class MessagesController implements NotificationCenter.NotificationCenter } req.users.add(getInputUser(user)); } - return ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, fragment, req); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); - } - }); - return; - } - final TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates(updates, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(updates.users, false); - putChats(updates.chats, false); - if (updates.chats != null && !updates.chats.isEmpty()) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); - } else { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); - } - } + return ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null) { + AndroidUtilities.runOnUIThread(() -> { + AlertsCreator.processError(currentAccount, error, fragment, req); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); }); + return; } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + AndroidUtilities.runOnUIThread(() -> { + putUsers(updates.users, false); + putChats(updates.chats, false); + if (updates.chats != null && !updates.chats.isEmpty()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); + } else { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); + } + }); }, ConnectionsManager.RequestFlagFailOnServerErrors); } else if (type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP) { final TLRPC.TL_channels_createChannel req = new TLRPC.TL_channels_createChannel(); @@ -5590,34 +5129,25 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { req.broadcast = true; } - return ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, fragment, req); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); - } - }); - return; - } - final TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates(updates, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(updates.users, false); - putChats(updates.chats, false); - if (updates.chats != null && !updates.chats.isEmpty()) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); - } else { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); - } - } + return ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null) { + AndroidUtilities.runOnUIThread(() -> { + AlertsCreator.processError(currentAccount, error, fragment, req); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); }); + return; } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + AndroidUtilities.runOnUIThread(() -> { + putUsers(updates.users, false); + putChats(updates.chats, false); + if (updates.chats != null && !updates.chats.isEmpty()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); + } else { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatDidFailCreate); + } + }); }, ConnectionsManager.RequestFlagFailOnServerErrors); } return 0; @@ -5630,54 +5160,42 @@ public class MessagesController implements NotificationCenter.NotificationCenter progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); - final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!((Activity) context).isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } + final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + AndroidUtilities.runOnUIThread(() -> { + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } - }); - TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates((TLRPC.Updates) response, false); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!((Activity) context).isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.show().setCanceledOnTouchOutside(true); - } + } + }); + TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates((TLRPC.Updates) response, false); + } else { + AndroidUtilities.runOnUIThread(() -> { + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } - }); - } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.show().setCanceledOnTouchOutside(true); + } + }); } }); - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); try { @@ -5694,20 +5212,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter final TLRPC.TL_channels_inviteToChannel req = new TLRPC.TL_channels_inviteToChannel(); req.channel = getInputChannel(chat_id); req.users = users; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, fragment, req, true); - } - }); - return; - } - processUpdates((TLRPC.Updates) response, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null) { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, fragment, req, true)); + return; } + processUpdates((TLRPC.Updates) response, false); }); } @@ -5715,12 +5225,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_toggleInvites req = new TLRPC.TL_channels_toggleInvites(); req.channel = getInputChannel(chat_id); req.enabled = enabled; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - processUpdates((TLRPC.Updates) response, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -5729,18 +5236,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_toggleSignatures req = new TLRPC.TL_channels_toggleSignatures(); req.channel = getInputChannel(chat_id); req.enabled = enabled; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL)); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -5749,18 +5248,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_togglePreHistoryHidden req = new TLRPC.TL_channels_togglePreHistoryHidden(); req.channel = getInputChannel(chat_id); req.enabled = enabled; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - processUpdates((TLRPC.Updates) response, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL)); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -5772,19 +5263,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_editAbout req = new TLRPC.TL_channels_editAbout(); req.channel = getInputChannel(chat_id); req.about = about; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_boolTrue) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - info.about = about; - MessagesStorage.getInstance(currentAccount).updateChatInfo(info, false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, false, null); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_boolTrue) { + AndroidUtilities.runOnUIThread(() -> { + info.about = about; + MessagesStorage.getInstance(currentAccount).updateChatInfo(info, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, false, null); + }); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -5793,27 +5278,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_channels_updateUsername req = new TLRPC.TL_channels_updateUsername(); req.channel = getInputChannel(chat_id); req.username = userName; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_boolTrue) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.Chat chat = getChat(chat_id); - if (userName.length() != 0) { - chat.flags |= TLRPC.CHAT_FLAG_IS_PUBLIC; - } else { - chat.flags &= ~TLRPC.CHAT_FLAG_IS_PUBLIC; - } - chat.username = userName; - ArrayList arrayList = new ArrayList<>(); - arrayList.add(chat); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(null, arrayList, true, true); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_boolTrue) { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.Chat chat = getChat(chat_id); + if (userName.length() != 0) { + chat.flags |= TLRPC.CHAT_FLAG_IS_PUBLIC; + } else { + chat.flags &= ~TLRPC.CHAT_FLAG_IS_PUBLIC; + } + chat.username = userName; + ArrayList arrayList = new ArrayList<>(); + arrayList.add(chat); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(null, arrayList, true, true); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); + }); } }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -5827,14 +5306,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.peer = getInputPeer(user.id); req.start_param = botHash; req.random_id = Utilities.random.nextLong(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error != null) { - return; - } - processUpdates((TLRPC.Updates) response, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null) { + return; } + processUpdates((TLRPC.Updates) response, false); }); } @@ -5842,13 +5318,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_messages_toggleChatAdmins req = new TLRPC.TL_messages_toggleChatAdmins(); req.chat_id = chat_id; req.enabled = enabled; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - processUpdates((TLRPC.Updates) response, false); - loadFullChat(chat_id, 0, true); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + processUpdates((TLRPC.Updates) response, false); + loadFullChat(chat_id, 0, true); } }); } @@ -5858,11 +5331,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.chat_id = chat_id; req.user_id = getInputUser(user_id); req.is_admin = admin; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -5914,52 +5384,34 @@ public class MessagesController implements NotificationCenter.NotificationCenter request = req; } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - joiningToChannels.remove((Integer) chat_id); - } - }); - } - if (error != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, fragment, request, isChannel && !isMegagroup); - } - }); - return; - } - boolean hasJoinMessage = false; - TLRPC.Updates updates = (TLRPC.Updates) response; - for (int a = 0; a < updates.updates.size(); a++) { - TLRPC.Update update = updates.updates.get(a); - if (update instanceof TLRPC.TL_updateNewChannelMessage) { - if (((TLRPC.TL_updateNewChannelMessage) update).message.action instanceof TLRPC.TL_messageActionChatAddUser) { - hasJoinMessage = true; - break; - } + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { + AndroidUtilities.runOnUIThread(() -> joiningToChannels.remove((Integer) chat_id)); + } + if (error != null) { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, fragment, request, isChannel && !isMegagroup)); + return; + } + boolean hasJoinMessage = false; + TLRPC.Updates updates = (TLRPC.Updates) response; + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateNewChannelMessage) { + if (((TLRPC.TL_updateNewChannelMessage) update).message.action instanceof TLRPC.TL_messageActionChatAddUser) { + hasJoinMessage = true; + break; } } - processUpdates(updates, false); - if (isChannel) { - if (!hasJoinMessage && inputUser instanceof TLRPC.TL_inputUserSelf) { - generateJoinMessage(chat_id, true); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadFullChat(chat_id, 0, true); - } - }, 1000); - } - if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { - MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(new ArrayList(), null, true, chat_id); + } + processUpdates(updates, false); + if (isChannel) { + if (!hasJoinMessage && inputUser instanceof TLRPC.TL_inputUserSelf) { + generateJoinMessage(chat_id, true); } + AndroidUtilities.runOnUIThread(() -> loadFullChat(chat_id, 0, true), 1000); + } + if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { + MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(new ArrayList<>(), null, true, chat_id); } }); } else { @@ -6033,30 +5485,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.user_id = getInputUser(user); request = req; } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - deleteDialog(-chat_id, 0); - } - }); - } - if (error != null) { - return; - } - final TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates(updates, false); - if (isChannel && !(inputUser instanceof TLRPC.TL_inputUserSelf)) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadFullChat(chat_id, 0, true); - } - }, 1000); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + AndroidUtilities.runOnUIThread(() -> deleteDialog(-chat_id, 0)); + } + if (error != null) { + return; + } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + if (isChannel && !(inputUser instanceof TLRPC.TL_inputUserSelf)) { + AndroidUtilities.runOnUIThread(() -> loadFullChat(chat_id, 0, true), 1000); } }, ConnectionsManager.RequestFlagInvokeAfter); } else { @@ -6099,14 +5538,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.title = title; request = req; } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error != null) { - return; - } - processUpdates((TLRPC.Updates) response, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (error != null) { + return; } + processUpdates((TLRPC.Updates) response, false); }, ConnectionsManager.RequestFlagInvokeAfter); } else { TLRPC.Chat chat = getChat(chat_id); @@ -6142,14 +5578,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter } request = req; } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error != null) { - return; - } - processUpdates((TLRPC.Updates) response, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (error != null) { + return; } + processUpdates((TLRPC.Updates) response, false); }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -6164,11 +5597,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.other_uids.add(userConfig.getClientUserId()); } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -6177,12 +5607,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (type == 1) { unregistedPush(); TLRPC.TL_auth_logOut req = new TLRPC.TL_auth_logOut(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - ConnectionsManager.getInstance(currentAccount).cleanup(false); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> ConnectionsManager.getInstance(currentAccount).cleanup(false)); } else { ConnectionsManager.getInstance(currentAccount).cleanup(type == 2); } @@ -6199,16 +5624,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter } TLRPC.TL_help_getAppChangelog req = new TLRPC.TL_help_getAppChangelog(); req.prev_app_version = SharedConfig.lastUpdateVersion; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - SharedConfig.lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; - SharedConfig.saveConfig(); - } - if (response instanceof TLRPC.Updates) { - processUpdates((TLRPC.Updates) response, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + SharedConfig.lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; + SharedConfig.saveConfig(); + } + if (response instanceof TLRPC.Updates) { + processUpdates((TLRPC.Updates) response, false); } }); } @@ -6234,27 +5656,23 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { UserConfig userConfig = UserConfig.getInstance(a); if (a != currentAccount && userConfig.isClientActivated()) { - req.other_uids.add(userConfig.getClientUserId()); + int uid = userConfig.getClientUserId(); + req.other_uids.add(uid); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("add other uid = " + uid + " for account " + currentAccount); + } } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_boolTrue) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("account " + currentAccount + " registered for push"); - } - UserConfig.getInstance(currentAccount).registeredForPush = true; - SharedConfig.pushString = regid; - UserConfig.getInstance(currentAccount).saveConfig(false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_boolTrue) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("account " + currentAccount + " registered for push"); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - registeringForPush = false; - } - }); + UserConfig.getInstance(currentAccount).registeredForPush = true; + SharedConfig.pushString = regid; + UserConfig.getInstance(currentAccount).saveConfig(false); } + AndroidUtilities.runOnUIThread(() -> registeringForPush = false); }); } @@ -6264,24 +5682,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter } updatingState = true; TLRPC.TL_updates_getState req = new TLRPC.TL_updates_getState(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - updatingState = false; - if (error == null) { - TLRPC.TL_updates_state res = (TLRPC.TL_updates_state) response; - MessagesStorage.getInstance(currentAccount).setLastDateValue(res.date); - MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.pts); - MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.seq); - MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.qts); - for (int a = 0; a < 3; a++) { - processUpdatesQueue(a, 2); - } - MessagesStorage.getInstance(currentAccount).saveDiffParams(MessagesStorage.getInstance(currentAccount).getLastSeqValue(), MessagesStorage.getInstance(currentAccount).getLastPtsValue(), MessagesStorage.getInstance(currentAccount).getLastDateValue(), MessagesStorage.getInstance(currentAccount).getLastQtsValue()); - } else { - if (error.code != 401) { - loadCurrentState(); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + updatingState = false; + if (error == null) { + TLRPC.TL_updates_state res = (TLRPC.TL_updates_state) response; + MessagesStorage.getInstance(currentAccount).setLastDateValue(res.date); + MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.pts); + MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.seq); + MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.qts); + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 2); + } + MessagesStorage.getInstance(currentAccount).saveDiffParams(MessagesStorage.getInstance(currentAccount).getLastSeqValue(), MessagesStorage.getInstance(currentAccount).getLastPtsValue(), MessagesStorage.getInstance(currentAccount).getLastDateValue(), MessagesStorage.getInstance(currentAccount).getLastQtsValue()); + } else { + if (error.code != 401) { + loadCurrentState(); } } }); @@ -6356,12 +5771,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter updatesQueueChannels.remove(channelId); return; } - Collections.sort(updatesQueue, new Comparator() { - @Override - public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { - return AndroidUtilities.compare(updates.pts, updates2.pts); - } - }); + Collections.sort(updatesQueue, (updates, updates2) -> AndroidUtilities.compare(updates.pts, updates2.pts)); boolean anyProceed = false; if (state == 2) { channelsPts.put(channelId, updatesQueue.get(0).pts); @@ -6416,28 +5826,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter ArrayList updatesQueue = null; if (type == 0) { updatesQueue = updatesQueueSeq; - Collections.sort(updatesQueue, new Comparator() { - @Override - public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { - return AndroidUtilities.compare(getUpdateSeq(updates), getUpdateSeq(updates2)); - } - }); + Collections.sort(updatesQueue, (updates, updates2) -> AndroidUtilities.compare(getUpdateSeq(updates), getUpdateSeq(updates2))); } else if (type == 1) { updatesQueue = updatesQueuePts; - Collections.sort(updatesQueue, new Comparator() { - @Override - public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { - return AndroidUtilities.compare(updates.pts, updates2.pts); - } - }); + Collections.sort(updatesQueue, (updates, updates2) -> AndroidUtilities.compare(updates.pts, updates2.pts)); } else if (type == 2) { updatesQueue = updatesQueueQts; - Collections.sort(updatesQueue, new Comparator() { - @Override - public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { - return AndroidUtilities.compare(updates.pts, updates2.pts); - } - }); + Collections.sort(updatesQueue, (updates, updates2) -> AndroidUtilities.compare(updates.pts, updates2.pts)); } if (updatesQueue != null && !updatesQueue.isEmpty()) { boolean anyProceed = false; @@ -6524,39 +5919,33 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { newTaskId = taskId; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; - if (!res.dialogs.isEmpty() && !res.chats.isEmpty()) { - TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); - dialogs.dialogs.addAll(res.dialogs); - dialogs.messages.addAll(res.messages); - dialogs.users.addAll(res.users); - dialogs.chats.addAll(res.chats); - processLoadedDialogs(dialogs, null, 0, 1, 2, false, false, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; + if (!res.dialogs.isEmpty() && !res.chats.isEmpty()) { + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + dialogs.dialogs.addAll(res.dialogs); + dialogs.messages.addAll(res.messages); + dialogs.users.addAll(res.users); + dialogs.chats.addAll(res.chats); + processLoadedDialogs(dialogs, null, 0, 1, 2, false, false, false); } - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } - gettingUnknownChannels.delete(channel.id); } + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); + } + gettingUnknownChannels.delete(channel.id); }); } public void startShortPoll(final int channelId, final boolean stop) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (stop) { - needShortPollChannels.delete(channelId); - } else { - needShortPollChannels.put(channelId, 0); - if (shortPollChannels.indexOfKey(channelId) < 0) { - getChannelDifference(channelId, 3, 0, null); - } + Utilities.stageQueue.postRunnable(() -> { + if (stop) { + needShortPollChannels.delete(channelId); + } else { + needShortPollChannels.put(channelId, 0); + if (shortPollChannels.indexOfKey(channelId) < 0) { + getChannelDifference(channelId, 3, 0, null); } } }); @@ -6653,208 +6042,177 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (BuildVars.LOGS_ENABLED) { FileLog.d("start getChannelDifference with pts = " + channelPts + " channelId = " + channelId); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - final TLRPC.updates_ChannelDifference res = (TLRPC.updates_ChannelDifference) response; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + final TLRPC.updates_ChannelDifference res = (TLRPC.updates_ChannelDifference) response; - final SparseArray usersDict = new SparseArray<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersDict.put(user.id, user); + final SparseArray usersDict = new SparseArray<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + TLRPC.Chat channel = null; + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + if (chat.id == channelId) { + channel = chat; + break; } - TLRPC.Chat channel = null; - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat chat = res.chats.get(a); - if (chat.id == channelId) { - channel = chat; - break; + } + final TLRPC.Chat channelFinal = channel; + + final ArrayList msgUpdates = new ArrayList<>(); + if (!res.other_updates.isEmpty()) { + for (int a = 0; a < res.other_updates.size(); a++) { + TLRPC.Update upd = res.other_updates.get(a); + if (upd instanceof TLRPC.TL_updateMessageID) { + msgUpdates.add((TLRPC.TL_updateMessageID) upd); + res.other_updates.remove(a); + a--; } } - final TLRPC.Chat channelFinal = channel; + } - final ArrayList msgUpdates = new ArrayList<>(); - if (!res.other_updates.isEmpty()) { - for (int a = 0; a < res.other_updates.size(); a++) { - TLRPC.Update upd = res.other_updates.get(a); - if (upd instanceof TLRPC.TL_updateMessageID) { - msgUpdates.add((TLRPC.TL_updateMessageID) upd); - res.other_updates.remove(a); - a--; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + AndroidUtilities.runOnUIThread(() -> { + putUsers(res.users, false); + putChats(res.chats, false); + }); + + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + if (!msgUpdates.isEmpty()) { + final SparseArray corrected = new SparseArray<>(); + for (TLRPC.TL_updateMessageID update : msgUpdates) { + long[] ids = MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(update.random_id, null, update.id, 0, false, channelId); + if (ids != null) { + corrected.put(update.id, ids); } } - } - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(res.users, false); - putChats(res.chats, false); - } - }); - - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - if (!msgUpdates.isEmpty()) { - final SparseArray corrected = new SparseArray<>(); - for (TLRPC.TL_updateMessageID update : msgUpdates) { - long[] ids = MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(update.random_id, null, update.id, 0, false, channelId); - if (ids != null) { - corrected.put(update.id, ids); - } - } - - if (corrected.size() != 0) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < corrected.size(); a++) { - int newId = corrected.keyAt(a); - long[] ids = corrected.valueAt(a); - int oldId = (int) ids[1]; - SendMessagesHelper.getInstance(currentAccount).processSentMessage(oldId); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0], 0L); - } - } - }); - } - } - - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (res instanceof TLRPC.TL_updates_channelDifference || res instanceof TLRPC.TL_updates_channelDifferenceEmpty) { - if (!res.new_messages.isEmpty()) { - final LongSparseArray> messages = new LongSparseArray<>(); - ImageLoader.saveMessagesThumbs(res.new_messages); - - final ArrayList pushMessages = new ArrayList<>(); - long dialog_id = -channelId; - Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); - if (inboxValue == null) { - inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); - dialogs_read_inbox_max.put(dialog_id, inboxValue); - } - - Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); - if (outboxValue == null) { - outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); - dialogs_read_outbox_max.put(dialog_id, outboxValue); - } - - for (int a = 0; a < res.new_messages.size(); a++) { - TLRPC.Message message = res.new_messages.get(a); - message.unread = !(channelFinal != null && channelFinal.left || (message.out ? outboxValue : inboxValue) >= message.id || message.action instanceof TLRPC.TL_messageActionChannelCreate); - if (channelFinal != null && channelFinal.megagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - - MessageObject obj = new MessageObject(currentAccount, message, usersDict, createdDialogIds.contains(dialog_id)); - if (!obj.isOut() && obj.isUnread()) { - pushMessages.add(obj); - } - - long uid = -channelId; - ArrayList arr = messages.get(uid); - if (arr == null) { - arr = new ArrayList<>(); - messages.put(uid, arr); - } - arr.add(obj); - } - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < messages.size(); a++) { - long key = messages.keyAt(a); - ArrayList value = messages.valueAt(a); - updateInterfaceWithMessages(key, value); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - }); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - if (!pushMessages.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false); - } - }); - } - MessagesStorage.getInstance(currentAccount).putMessages(res.new_messages, true, false, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); - } - }); - } - - if (!res.other_updates.isEmpty()) { - processUpdateArray(res.other_updates, res.users, res.chats, true); - } - processChannelsUpdatesQueue(channelId, 1); - MessagesStorage.getInstance(currentAccount).saveChannelPts(channelId, res.pts); - } else if (res instanceof TLRPC.TL_updates_channelDifferenceTooLong) { - long dialog_id = -channelId; - - Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); - if (inboxValue == null) { - inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); - dialogs_read_inbox_max.put(dialog_id, inboxValue); - } - - Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); - if (outboxValue == null) { - outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); - dialogs_read_outbox_max.put(dialog_id, outboxValue); - } - - for (int a = 0; a < res.messages.size(); a++) { - TLRPC.Message message = res.messages.get(a); - message.dialog_id = -channelId; - message.unread = !(message.action instanceof TLRPC.TL_messageActionChannelCreate || channelFinal != null && channelFinal.left || (message.out ? outboxValue : inboxValue) >= message.id); - if (channelFinal != null && channelFinal.megagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } - MessagesStorage.getInstance(currentAccount).overwriteChannel(channelId, (TLRPC.TL_updates_channelDifferenceTooLong) res, newDialogType); - } - gettingDifferenceChannels.delete(channelId); - channelsPts.put(channelId, res.pts); - - if ((res.flags & 2) != 0) { - shortPollChannels.put(channelId, (int) (System.currentTimeMillis() / 1000) + res.timeout); - } - if (!res.isFinal) { - getChannelDifference(channelId); - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("received channel difference with pts = " + res.pts + " channelId = " + channelId); - FileLog.d("new_messages = " + res.new_messages.size() + " messages = " + res.messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); - } - - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + if (corrected.size() != 0) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < corrected.size(); a++) { + int newId = corrected.keyAt(a); + long[] ids = corrected.valueAt(a); + int oldId = (int) ids[1]; + SendMessagesHelper.getInstance(currentAccount).processSentMessage(oldId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0], 0L); } }); } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkChannelError(error.text, channelId); + } + + Utilities.stageQueue.postRunnable(() -> { + if (res instanceof TLRPC.TL_updates_channelDifference || res instanceof TLRPC.TL_updates_channelDifferenceEmpty) { + if (!res.new_messages.isEmpty()) { + final LongSparseArray> messages = new LongSparseArray<>(); + ImageLoader.saveMessagesThumbs(res.new_messages); + + final ArrayList pushMessages = new ArrayList<>(); + long dialog_id = -channelId; + Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); + if (inboxValue == null) { + inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); + dialogs_read_inbox_max.put(dialog_id, inboxValue); + } + + Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); + if (outboxValue == null) { + outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); + dialogs_read_outbox_max.put(dialog_id, outboxValue); + } + + for (int a = 0; a < res.new_messages.size(); a++) { + TLRPC.Message message = res.new_messages.get(a); + message.unread = !(channelFinal != null && channelFinal.left || (message.out ? outboxValue : inboxValue) >= message.id || message.action instanceof TLRPC.TL_messageActionChannelCreate); + if (channelFinal != null && channelFinal.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + + MessageObject obj = new MessageObject(currentAccount, message, usersDict, createdDialogIds.contains(dialog_id)); + if (!obj.isOut() && obj.isUnread()) { + pushMessages.add(obj); + } + + long uid = -channelId; + ArrayList arr = messages.get(uid); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(uid, arr); + } + arr.add(obj); + } + + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < messages.size(); a++) { + long key = messages.keyAt(a); + ArrayList value = messages.valueAt(a); + updateInterfaceWithMessages(key, value); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + if (!pushMessages.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false)); + } + MessagesStorage.getInstance(currentAccount).putMessages(res.new_messages, true, false, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); + }); + } + + if (!res.other_updates.isEmpty()) { + processUpdateArray(res.other_updates, res.users, res.chats, true); + } + processChannelsUpdatesQueue(channelId, 1); + MessagesStorage.getInstance(currentAccount).saveChannelPts(channelId, res.pts); + } else if (res instanceof TLRPC.TL_updates_channelDifferenceTooLong) { + long dialog_id = -channelId; + + Integer inboxValue = dialogs_read_inbox_max.get(dialog_id); + if (inboxValue == null) { + inboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id); + dialogs_read_inbox_max.put(dialog_id, inboxValue); + } + + Integer outboxValue = dialogs_read_outbox_max.get(dialog_id); + if (outboxValue == null) { + outboxValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, dialog_id); + dialogs_read_outbox_max.put(dialog_id, outboxValue); + } + + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + message.dialog_id = -channelId; + message.unread = !(message.action instanceof TLRPC.TL_messageActionChannelCreate || channelFinal != null && channelFinal.left || (message.out ? outboxValue : inboxValue) >= message.id); + if (channelFinal != null && channelFinal.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + MessagesStorage.getInstance(currentAccount).overwriteChannel(channelId, (TLRPC.TL_updates_channelDifferenceTooLong) res, newDialogType); + } + gettingDifferenceChannels.delete(channelId); + channelsPts.put(channelId, res.pts); + + if ((res.flags & 2) != 0) { + shortPollChannels.put(channelId, (int) (System.currentTimeMillis() / 1000) + res.timeout); + } + if (!res.isFinal) { + getChannelDifference(channelId); + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("received channel difference with pts = " + res.pts + " channelId = " + channelId); + FileLog.d("new_messages = " + res.new_messages.size() + " messages = " + res.messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); + } + + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); - gettingDifferenceChannels.delete(channelId); - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + }); + } else { + AndroidUtilities.runOnUIThread(() -> checkChannelError(error.text, channelId)); + gettingDifferenceChannels.delete(channelId); + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } } }); @@ -6908,241 +6266,212 @@ public class MessagesController implements NotificationCenter.NotificationCenter FileLog.d("start getDifference with date = " + date + " pts = " + pts + " qts = " + qts); } ConnectionsManager.getInstance(currentAccount).setIsUpdating(true); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - final TLRPC.updates_Difference res = (TLRPC.updates_Difference) response; - if (res instanceof TLRPC.TL_updates_differenceTooLong) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadedFullUsers.clear(); - loadedFullChats.clear(); - resetDialogs(true, MessagesStorage.getInstance(currentAccount).getLastSeqValue(), res.pts, date, qts); - } - }); - } else { - if (res instanceof TLRPC.TL_updates_differenceSlice) { - getDifference(res.intermediate_state.pts, res.intermediate_state.date, res.intermediate_state.qts, true); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + final TLRPC.updates_Difference res = (TLRPC.updates_Difference) response; + if (res instanceof TLRPC.TL_updates_differenceTooLong) { + AndroidUtilities.runOnUIThread(() -> { + loadedFullUsers.clear(); + loadedFullChats.clear(); + resetDialogs(true, MessagesStorage.getInstance(currentAccount).getLastSeqValue(), res.pts, date, qts); + }); + } else { + if (res instanceof TLRPC.TL_updates_differenceSlice) { + getDifference(res.intermediate_state.pts, res.intermediate_state.date, res.intermediate_state.qts, true); + } - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersDict.put(user.id, user); - } - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat chat = res.chats.get(a); - chatsDict.put(chat.id, chat); - } + final SparseArray usersDict = new SparseArray<>(); + final SparseArray chatsDict = new SparseArray<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + chatsDict.put(chat.id, chat); + } - final ArrayList msgUpdates = new ArrayList<>(); - if (!res.other_updates.isEmpty()) { - for (int a = 0; a < res.other_updates.size(); a++) { - TLRPC.Update upd = res.other_updates.get(a); - if (upd instanceof TLRPC.TL_updateMessageID) { - msgUpdates.add((TLRPC.TL_updateMessageID) upd); + final ArrayList msgUpdates = new ArrayList<>(); + if (!res.other_updates.isEmpty()) { + for (int a = 0; a < res.other_updates.size(); a++) { + TLRPC.Update upd = res.other_updates.get(a); + if (upd instanceof TLRPC.TL_updateMessageID) { + msgUpdates.add((TLRPC.TL_updateMessageID) upd); + res.other_updates.remove(a); + a--; + } else if (getUpdateType(upd) == 2) { + int channelId = getUpdateChannelId(upd); + int channelPts = channelsPts.get(channelId); + if (channelPts == 0) { + channelPts = MessagesStorage.getInstance(currentAccount).getChannelPtsSync(channelId); + if (channelPts != 0) { + channelsPts.put(channelId, channelPts); + } + } + if (channelPts != 0 && getUpdatePts(upd) <= channelPts) { res.other_updates.remove(a); a--; - } else if (getUpdateType(upd) == 2) { - int channelId = getUpdateChannelId(upd); - int channelPts = channelsPts.get(channelId); - if (channelPts == 0) { - channelPts = MessagesStorage.getInstance(currentAccount).getChannelPtsSync(channelId); - if (channelPts != 0) { - channelsPts.put(channelId, channelPts); - } - } - if (channelPts != 0 && getUpdatePts(upd) <= channelPts) { - res.other_updates.remove(a); - a--; - } } } } + } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadedFullUsers.clear(); - loadedFullChats.clear(); - putUsers(res.users, false); - putChats(res.chats, false); - } - }); + AndroidUtilities.runOnUIThread(() -> { + loadedFullUsers.clear(); + loadedFullChats.clear(); + putUsers(res.users, false); + putChats(res.chats, false); + }); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, false); - if (!msgUpdates.isEmpty()) { - final SparseArray corrected = new SparseArray<>(); - for (int a = 0; a < msgUpdates.size(); a++) { - TLRPC.TL_updateMessageID update = msgUpdates.get(a); - long[] ids = MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(update.random_id, null, update.id, 0, false, 0); - if (ids != null) { - corrected.put(update.id, ids); - } - } - - if (corrected.size() != 0) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < corrected.size(); a++) { - int newId = corrected.keyAt(a); - long[] ids = corrected.valueAt(a); - int oldId = (int) ids[1]; - SendMessagesHelper.getInstance(currentAccount).processSentMessage(oldId); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0], 0L); - } - } - }); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, false); + if (!msgUpdates.isEmpty()) { + final SparseArray corrected = new SparseArray<>(); + for (int a = 0; a < msgUpdates.size(); a++) { + TLRPC.TL_updateMessageID update = msgUpdates.get(a); + long[] ids = MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(update.random_id, null, update.id, 0, false, 0); + if (ids != null) { + corrected.put(update.id, ids); } + } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (!res.new_messages.isEmpty() || !res.new_encrypted_messages.isEmpty()) { - final LongSparseArray> messages = new LongSparseArray<>(); - for (int b = 0; b < res.new_encrypted_messages.size(); b++) { - TLRPC.EncryptedMessage encryptedMessage = res.new_encrypted_messages.get(b); - ArrayList decryptedMessages = SecretChatHelper.getInstance(currentAccount).decryptMessage(encryptedMessage); - if (decryptedMessages != null && !decryptedMessages.isEmpty()) { - res.new_messages.addAll(decryptedMessages); - } - } - - ImageLoader.saveMessagesThumbs(res.new_messages); - - final ArrayList pushMessages = new ArrayList<>(); - int clientUserId = UserConfig.getInstance(currentAccount).getClientUserId(); - for (int a = 0; a < res.new_messages.size(); a++) { - TLRPC.Message message = res.new_messages.get(a); - if (message.dialog_id == 0) { - if (message.to_id.chat_id != 0) { - message.dialog_id = -message.to_id.chat_id; - } else { - if (message.to_id.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - message.to_id.user_id = message.from_id; - } - message.dialog_id = message.to_id.user_id; - } - } - - if ((int) message.dialog_id != 0) { - if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { - TLRPC.User user = usersDict.get(message.action.user_id); - if (user != null && user.bot) { - message.reply_markup = new TLRPC.TL_replyKeyboardHide(); - message.flags |= 64; - } - } - if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { - message.unread = false; - message.media_unread = false; - } else { - ConcurrentHashMap read_max = message.out ? dialogs_read_outbox_max : dialogs_read_inbox_max; - Integer value = read_max.get(message.dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); - read_max.put(message.dialog_id, value); - } - message.unread = value < message.id; - } - } - if (message.dialog_id == clientUserId) { - message.unread = false; - message.media_unread = false; - message.out = true; - } - - MessageObject obj = new MessageObject(currentAccount, message, usersDict, chatsDict, createdDialogIds.contains(message.dialog_id)); - - if (!obj.isOut() && obj.isUnread()) { - pushMessages.add(obj); - } - - ArrayList arr = messages.get(message.dialog_id); - if (arr == null) { - arr = new ArrayList<>(); - messages.put(message.dialog_id, arr); - } - arr.add(obj); - } - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < messages.size(); a++) { - long key = messages.keyAt(a); - ArrayList value = messages.valueAt(a); - updateInterfaceWithMessages(key, value); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - }); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - if (!pushMessages.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, !(res instanceof TLRPC.TL_updates_differenceSlice), false); - } - }); - } - MessagesStorage.getInstance(currentAccount).putMessages(res.new_messages, true, false, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); - } - }); - - SecretChatHelper.getInstance(currentAccount).processPendingEncMessages(); - } - - if (!res.other_updates.isEmpty()) { - processUpdateArray(res.other_updates, res.users, res.chats, true); - } - - if (res instanceof TLRPC.TL_updates_difference) { - gettingDifference = false; - MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.state.seq); - MessagesStorage.getInstance(currentAccount).setLastDateValue(res.state.date); - MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.state.pts); - MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.state.qts); - ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); - for (int a = 0; a < 3; a++) { - processUpdatesQueue(a, 1); - } - } else if (res instanceof TLRPC.TL_updates_differenceSlice) { - MessagesStorage.getInstance(currentAccount).setLastDateValue(res.intermediate_state.date); - MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.intermediate_state.pts); - MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.intermediate_state.qts); - } else if (res instanceof TLRPC.TL_updates_differenceEmpty) { - gettingDifference = false; - MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.seq); - MessagesStorage.getInstance(currentAccount).setLastDateValue(res.date); - ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); - for (int a = 0; a < 3; a++) { - processUpdatesQueue(a, 1); - } - } - MessagesStorage.getInstance(currentAccount).saveDiffParams(MessagesStorage.getInstance(currentAccount).getLastSeqValue(), MessagesStorage.getInstance(currentAccount).getLastPtsValue(), MessagesStorage.getInstance(currentAccount).getLastDateValue(), MessagesStorage.getInstance(currentAccount).getLastQtsValue()); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("received difference with date = " + MessagesStorage.getInstance(currentAccount).getLastDateValue() + " pts = " + MessagesStorage.getInstance(currentAccount).getLastPtsValue() + " seq = " + MessagesStorage.getInstance(currentAccount).getLastSeqValue() + " messages = " + res.new_messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); - } + if (corrected.size() != 0) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < corrected.size(); a++) { + int newId = corrected.keyAt(a); + long[] ids = corrected.valueAt(a); + int oldId = (int) ids[1]; + SendMessagesHelper.getInstance(currentAccount).processSentMessage(oldId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0], 0L); } }); } + } + + Utilities.stageQueue.postRunnable(() -> { + if (!res.new_messages.isEmpty() || !res.new_encrypted_messages.isEmpty()) { + final LongSparseArray> messages = new LongSparseArray<>(); + for (int b = 0; b < res.new_encrypted_messages.size(); b++) { + TLRPC.EncryptedMessage encryptedMessage = res.new_encrypted_messages.get(b); + ArrayList decryptedMessages = SecretChatHelper.getInstance(currentAccount).decryptMessage(encryptedMessage); + if (decryptedMessages != null && !decryptedMessages.isEmpty()) { + res.new_messages.addAll(decryptedMessages); + } + } + + ImageLoader.saveMessagesThumbs(res.new_messages); + + final ArrayList pushMessages = new ArrayList<>(); + int clientUserId = UserConfig.getInstance(currentAccount).getClientUserId(); + for (int a = 0; a < res.new_messages.size(); a++) { + TLRPC.Message message = res.new_messages.get(a); + if (message.dialog_id == 0) { + if (message.to_id.chat_id != 0) { + message.dialog_id = -message.to_id.chat_id; + } else { + if (message.to_id.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { + message.to_id.user_id = message.from_id; + } + message.dialog_id = message.to_id.user_id; + } + } + + if ((int) message.dialog_id != 0) { + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + message.flags |= 64; + } + } + if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } else { + ConcurrentHashMap read_max = message.out ? dialogs_read_outbox_max : dialogs_read_inbox_max; + Integer value = read_max.get(message.dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); + read_max.put(message.dialog_id, value); + } + message.unread = value < message.id; + } + } + if (message.dialog_id == clientUserId) { + message.unread = false; + message.media_unread = false; + message.out = true; + } + + MessageObject obj = new MessageObject(currentAccount, message, usersDict, chatsDict, createdDialogIds.contains(message.dialog_id)); + + if (!obj.isOut() && obj.isUnread()) { + pushMessages.add(obj); + } + + ArrayList arr = messages.get(message.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(message.dialog_id, arr); + } + arr.add(obj); + } + + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < messages.size(); a++) { + long key = messages.keyAt(a); + ArrayList value = messages.valueAt(a); + updateInterfaceWithMessages(key, value); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + if (!pushMessages.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, !(res instanceof TLRPC.TL_updates_differenceSlice), false)); + } + MessagesStorage.getInstance(currentAccount).putMessages(res.new_messages, true, false, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); + }); + + SecretChatHelper.getInstance(currentAccount).processPendingEncMessages(); + } + + if (!res.other_updates.isEmpty()) { + processUpdateArray(res.other_updates, res.users, res.chats, true); + } + + if (res instanceof TLRPC.TL_updates_difference) { + gettingDifference = false; + MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.state.seq); + MessagesStorage.getInstance(currentAccount).setLastDateValue(res.state.date); + MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.state.pts); + MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.state.qts); + ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 1); + } + } else if (res instanceof TLRPC.TL_updates_differenceSlice) { + MessagesStorage.getInstance(currentAccount).setLastDateValue(res.intermediate_state.date); + MessagesStorage.getInstance(currentAccount).setLastPtsValue(res.intermediate_state.pts); + MessagesStorage.getInstance(currentAccount).setLastQtsValue(res.intermediate_state.qts); + } else if (res instanceof TLRPC.TL_updates_differenceEmpty) { + gettingDifference = false; + MessagesStorage.getInstance(currentAccount).setLastSeqValue(res.seq); + MessagesStorage.getInstance(currentAccount).setLastDateValue(res.date); + ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 1); + } + } + MessagesStorage.getInstance(currentAccount).saveDiffParams(MessagesStorage.getInstance(currentAccount).getLastSeqValue(), MessagesStorage.getInstance(currentAccount).getLastPtsValue(), MessagesStorage.getInstance(currentAccount).getLastDateValue(), MessagesStorage.getInstance(currentAccount).getLastQtsValue()); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("received difference with date = " + MessagesStorage.getInstance(currentAccount).getLastDateValue() + " pts = " + MessagesStorage.getInstance(currentAccount).getLastPtsValue() + " seq = " + MessagesStorage.getInstance(currentAccount).getLastSeqValue() + " messages = " + res.new_messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); + } }); - } - } else { - gettingDifference = false; - ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); + }); } + } else { + gettingDifference = false; + ConnectionsManager.getInstance(currentAccount).setIsUpdating(false); } }); } @@ -7202,12 +6531,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newTaskId = taskId; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); } @@ -7219,49 +6545,41 @@ public class MessagesController implements NotificationCenter.NotificationCenter } loadingUnreadDialogs = true; TLRPC.TL_messages_getDialogUnreadMarks req = new TLRPC.TL_messages_getDialogUnreadMarks(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - final TLRPC.Vector vector = (TLRPC.Vector) response; - for (int a = 0, size = vector.objects.size(); a < size; a++) { - TLRPC.DialogPeer peer = (TLRPC.DialogPeer) vector.objects.get(a); - if (peer instanceof TLRPC.TL_dialogPeer) { - TLRPC.TL_dialogPeer dialogPeer = (TLRPC.TL_dialogPeer) peer; - long did; - if (dialogPeer.peer.user_id != 0) { - if (dialogPeer.peer.user_id != 0) { - did = dialogPeer.peer.user_id; - } else if (dialogPeer.peer.chat_id != 0) { - did = -dialogPeer.peer.chat_id; - } else { - did = -dialogPeer.peer.channel_id; - } - } else { - did = 0; - } - MessagesStorage.getInstance(currentAccount).setDialogUnread(did, true); - TLRPC.TL_dialog dialog = dialogs_dict.get(did); - if (dialog != null && !dialog.unread_mark) { - dialog.unread_mark = true; - if (dialog.unread_count == 0 && !isDialogMuted(did)) { - unreadUnmutedDialogs++; - } - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + final TLRPC.Vector vector = (TLRPC.Vector) response; + for (int a = 0, size = vector.objects.size(); a < size; a++) { + TLRPC.DialogPeer peer = (TLRPC.DialogPeer) vector.objects.get(a); + if (peer instanceof TLRPC.TL_dialogPeer) { + TLRPC.TL_dialogPeer dialogPeer = (TLRPC.TL_dialogPeer) peer; + long did; + if (dialogPeer.peer.user_id != 0) { + if (dialogPeer.peer.user_id != 0) { + did = dialogPeer.peer.user_id; + } else if (dialogPeer.peer.chat_id != 0) { + did = -dialogPeer.peer.chat_id; + } else { + did = -dialogPeer.peer.channel_id; + } + } else { + did = 0; + } + MessagesStorage.getInstance(currentAccount).setDialogUnread(did, true); + TLRPC.TL_dialog dialog = dialogs_dict.get(did); + if (dialog != null && !dialog.unread_mark) { + dialog.unread_mark = true; + if (dialog.unread_count == 0 && !isDialogMuted(did)) { + unreadUnmutedDialogs++; } - UserConfig.getInstance(currentAccount).unreadDialogsLoaded = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); - loadingUnreadDialogs = false; } } - }); + } + UserConfig.getInstance(currentAccount).unreadDialogsLoaded = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); + loadingUnreadDialogs = false; } - }); + })); } public boolean pinDialog(long did, boolean pin, TLRPC.InputPeer peer, long taskId) { @@ -7320,12 +6638,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newTaskId = taskId; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); } @@ -7339,199 +6654,188 @@ public class MessagesController implements NotificationCenter.NotificationCenter return; } TLRPC.TL_messages_getPinnedDialogs req = new TLRPC.TL_messages_getPinnedDialogs(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - final TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; - final TLRPC.TL_messages_dialogs toCache = new TLRPC.TL_messages_dialogs(); - toCache.users.addAll(res.users); - toCache.chats.addAll(res.chats); - toCache.dialogs.addAll(res.dialogs); - toCache.messages.addAll(res.messages); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + final TLRPC.TL_messages_peerDialogs res = (TLRPC.TL_messages_peerDialogs) response; + final TLRPC.TL_messages_dialogs toCache = new TLRPC.TL_messages_dialogs(); + toCache.users.addAll(res.users); + toCache.chats.addAll(res.chats); + toCache.dialogs.addAll(res.dialogs); + toCache.messages.addAll(res.messages); - final LongSparseArray new_dialogMessage = new LongSparseArray<>(); - final SparseArray usersDict = new SparseArray<>(); - final SparseArray chatsDict = new SparseArray<>(); - final ArrayList newPinnedOrder = new ArrayList<>(); + final LongSparseArray new_dialogMessage = new LongSparseArray<>(); + final SparseArray usersDict = new SparseArray<>(); + final SparseArray chatsDict = new SparseArray<>(); + final ArrayList newPinnedOrder = new ArrayList<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User u = res.users.get(a); - usersDict.put(u.id, u); - } - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat c = res.chats.get(a); - chatsDict.put(c.id, c); - } - - for (int a = 0; a < res.messages.size(); a++) { - TLRPC.Message message = res.messages.get(a); - if (message.to_id.channel_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); - if (chat != null && chat.left) { - continue; - } - } else if (message.to_id.chat_id != 0) { - TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); - if (chat != null && chat.migrated_to != null) { - continue; - } - } - MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); - new_dialogMessage.put(messageObject.getDialogId(), messageObject); - } - for (int a = 0; a < res.dialogs.size(); a++) { - TLRPC.TL_dialog d = res.dialogs.get(a); - if (d.id == 0) { - if (d.peer.user_id != 0) { - d.id = d.peer.user_id; - } else if (d.peer.chat_id != 0) { - d.id = -d.peer.chat_id; - } else if (d.peer.channel_id != 0) { - d.id = -d.peer.channel_id; - } - } - newPinnedOrder.add(d.id); - if (DialogObject.isChannel(d)) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.left) { - continue; - } - } else if ((int) d.id < 0) { - TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.migrated_to != null) { - continue; - } - } - if (d.last_message_date == 0) { - MessageObject mess = new_dialogMessage.get(d.id); - if (mess != null) { - d.last_message_date = mess.messageOwner.date; - } - } - - Integer value = dialogs_read_inbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); - - value = dialogs_read_outbox_max.get(d.id); - if (value == null) { - value = 0; - } - dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); - } - - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - applyDialogsNotificationsSettings(res.dialogs); - boolean changed = false; - boolean added = false; - int maxPinnedNum = 0; - LongSparseArray oldPinnedDialogNums = new LongSparseArray<>(); - ArrayList oldPinnedOrder = new ArrayList<>(); - for (int a = 0; a < dialogs.size(); a++) { - TLRPC.TL_dialog dialog = dialogs.get(a); - if ((int) dialog.id == 0) { - continue; - } - if (!dialog.pinned) { - break; - } - maxPinnedNum = Math.max(dialog.pinnedNum, maxPinnedNum); - oldPinnedDialogNums.put(dialog.id, dialog.pinnedNum); - oldPinnedOrder.add(dialog.id); - dialog.pinned = false; - dialog.pinnedNum = 0; - changed = true; - } - - ArrayList pinnedDialogs = new ArrayList<>(); - ArrayList orderArrayList = order != null ? order : newPinnedOrder; - if (orderArrayList.size() < oldPinnedOrder.size()) { - orderArrayList.add(0L); - } - while (oldPinnedOrder.size() < orderArrayList.size()) { - oldPinnedOrder.add(0, 0L); - } - if (!res.dialogs.isEmpty()) { - putUsers(res.users, false); - putChats(res.chats, false); - for (int a = 0; a < res.dialogs.size(); a++) { - TLRPC.TL_dialog dialog = res.dialogs.get(a); - if (newDialogId != 0) { - Integer oldNum = oldPinnedDialogNums.get(dialog.id); - if (oldNum != null) { - dialog.pinnedNum = oldNum; - } - } else { - int oldIdx = oldPinnedOrder.indexOf(dialog.id); - int newIdx = orderArrayList.indexOf(dialog.id); - if (oldIdx != -1 && newIdx != -1) { - if (oldIdx == newIdx) { - Integer oldNum = oldPinnedDialogNums.get(dialog.id); - if (oldNum != null) { - dialog.pinnedNum = oldNum; - } - } else { - long oldDid = oldPinnedOrder.get(newIdx); - Integer oldNum = oldPinnedDialogNums.get(oldDid); - if (oldNum != null) { - dialog.pinnedNum = oldNum; - } - } - } - } - if (dialog.pinnedNum == 0) { - dialog.pinnedNum = (res.dialogs.size() - a) + maxPinnedNum; - } - pinnedDialogs.add(dialog.id); - TLRPC.TL_dialog d = dialogs_dict.get(dialog.id); - - if (d != null) { - d.pinned = true; - d.pinnedNum = dialog.pinnedNum; - MessagesStorage.getInstance(currentAccount).setDialogPinned(dialog.id, dialog.pinnedNum); - } else { - added = true; - dialogs_dict.put(dialog.id, dialog); - MessageObject messageObject = new_dialogMessage.get(dialog.id); - dialogMessage.put(dialog.id, messageObject); - if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } - } - - changed = true; - } - } - if (changed) { - if (added) { - dialogs.clear(); - for (int a = 0, size = dialogs_dict.size(); a < size; a++) { - dialogs.add(dialogs_dict.valueAt(a)); - } - } - sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - MessagesStorage.getInstance(currentAccount).unpinAllDialogsExceptNew(pinnedDialogs); - MessagesStorage.getInstance(currentAccount).putDialogs(toCache, 1); - UserConfig.getInstance(currentAccount).pinnedDialogsLoaded = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - } - }); - } - }); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User u = res.users.get(a); + usersDict.put(u.id, u); } + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat c = res.chats.get(a); + chatsDict.put(c.id, c); + } + + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + if (message.to_id.channel_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); + if (chat != null && chat.left) { + continue; + } + } else if (message.to_id.chat_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, false); + new_dialogMessage.put(messageObject.getDialogId(), messageObject); + } + for (int a = 0; a < res.dialogs.size(); a++) { + TLRPC.TL_dialog d = res.dialogs.get(a); + if (d.id == 0) { + if (d.peer.user_id != 0) { + d.id = d.peer.user_id; + } else if (d.peer.chat_id != 0) { + d.id = -d.peer.chat_id; + } else if (d.peer.channel_id != 0) { + d.id = -d.peer.channel_id; + } + } + newPinnedOrder.add(d.id); + if (DialogObject.isChannel(d)) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.left) { + continue; + } + } else if ((int) d.id < 0) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + + Integer value = dialogs_read_inbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); + + value = dialogs_read_outbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_outbox_max.put(d.id, Math.max(value, d.read_outbox_max_id)); + } + + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + applyDialogsNotificationsSettings(res.dialogs); + boolean changed = false; + boolean added = false; + int maxPinnedNum = 0; + LongSparseArray oldPinnedDialogNums = new LongSparseArray<>(); + ArrayList oldPinnedOrder = new ArrayList<>(); + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.TL_dialog dialog = dialogs.get(a); + if ((int) dialog.id == 0) { + continue; + } + if (!dialog.pinned) { + break; + } + maxPinnedNum = Math.max(dialog.pinnedNum, maxPinnedNum); + oldPinnedDialogNums.put(dialog.id, dialog.pinnedNum); + oldPinnedOrder.add(dialog.id); + dialog.pinned = false; + dialog.pinnedNum = 0; + changed = true; + } + + ArrayList pinnedDialogs = new ArrayList<>(); + ArrayList orderArrayList = order != null ? order : newPinnedOrder; + if (orderArrayList.size() < oldPinnedOrder.size()) { + orderArrayList.add(0L); + } + while (oldPinnedOrder.size() < orderArrayList.size()) { + oldPinnedOrder.add(0, 0L); + } + if (!res.dialogs.isEmpty()) { + putUsers(res.users, false); + putChats(res.chats, false); + for (int a = 0; a < res.dialogs.size(); a++) { + TLRPC.TL_dialog dialog = res.dialogs.get(a); + if (newDialogId != 0) { + Integer oldNum = oldPinnedDialogNums.get(dialog.id); + if (oldNum != null) { + dialog.pinnedNum = oldNum; + } + } else { + int oldIdx = oldPinnedOrder.indexOf(dialog.id); + int newIdx = orderArrayList.indexOf(dialog.id); + if (oldIdx != -1 && newIdx != -1) { + if (oldIdx == newIdx) { + Integer oldNum = oldPinnedDialogNums.get(dialog.id); + if (oldNum != null) { + dialog.pinnedNum = oldNum; + } + } else { + long oldDid = oldPinnedOrder.get(newIdx); + Integer oldNum = oldPinnedDialogNums.get(oldDid); + if (oldNum != null) { + dialog.pinnedNum = oldNum; + } + } + } + } + if (dialog.pinnedNum == 0) { + dialog.pinnedNum = (res.dialogs.size() - a) + maxPinnedNum; + } + pinnedDialogs.add(dialog.id); + TLRPC.TL_dialog d = dialogs_dict.get(dialog.id); + + if (d != null) { + d.pinned = true; + d.pinnedNum = dialog.pinnedNum; + MessagesStorage.getInstance(currentAccount).setDialogPinned(dialog.id, dialog.pinnedNum); + } else { + added = true; + dialogs_dict.put(dialog.id, dialog); + MessageObject messageObject = new_dialogMessage.get(dialog.id); + dialogMessage.put(dialog.id, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + } + + changed = true; + } + } + if (changed) { + if (added) { + dialogs.clear(); + for (int a = 0, size = dialogs_dict.size(); a < size; a++) { + dialogs.add(dialogs_dict.valueAt(a)); + } + } + sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + } + MessagesStorage.getInstance(currentAccount).unpinAllDialogsExceptNew(pinnedDialogs); + MessagesStorage.getInstance(currentAccount).putDialogs(toCache, 1); + UserConfig.getInstance(currentAccount).pinnedDialogsLoaded = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + })); } }); } @@ -7565,110 +6869,73 @@ public class MessagesController implements NotificationCenter.NotificationCenter MessageObject obj = new MessageObject(currentAccount, message, true); pushMessages.add(obj); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false); - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false))); MessagesStorage.getInstance(currentAccount).putMessages(messagesArr, true, true, false, 0); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - updateInterfaceWithMessages(-chat_id, pushMessages); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } + AndroidUtilities.runOnUIThread(() -> { + updateInterfaceWithMessages(-chat_id, pushMessages); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); }); } public void checkChannelInviter(final int chat_id) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - final TLRPC.Chat chat = getChat(chat_id); - if (chat == null || !ChatObject.isChannel(chat_id, currentAccount) || chat.creator) { - return; - } - TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); - req.channel = getInputChannel(chat_id); - req.user_id = new TLRPC.TL_inputUserSelf(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - final TLRPC.TL_channels_channelParticipant res = (TLRPC.TL_channels_channelParticipant) response; - if (res != null && res.participant instanceof TLRPC.TL_channelParticipantSelf && res.participant.inviter_id != UserConfig.getInstance(currentAccount).getClientUserId()) { - if (chat.megagroup && MessagesStorage.getInstance(currentAccount).isMigratedChat(chat.id)) { - return; - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(res.users, false); - } - }); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); - - TLRPC.TL_messageService message = new TLRPC.TL_messageService(); - message.media_unread = true; - message.unread = true; - message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; - message.post = true; - if (chat.megagroup) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - message.local_id = message.id = UserConfig.getInstance(currentAccount).getNewMessageId(); - message.date = res.participant.date; - message.action = new TLRPC.TL_messageActionChatAddUser(); - message.from_id = res.participant.inviter_id; - message.action.users.add(UserConfig.getInstance(currentAccount).getClientUserId()); - message.to_id = new TLRPC.TL_peerChannel(); - message.to_id.channel_id = chat_id; - message.dialog_id = -chat_id; - UserConfig.getInstance(currentAccount).saveConfig(false); - - final ArrayList pushMessages = new ArrayList<>(); - final ArrayList messagesArr = new ArrayList<>(); - - ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersDict.put(user.id, user); - } - - messagesArr.add(message); - MessageObject obj = new MessageObject(currentAccount, message, usersDict, true); - pushMessages.add(obj); - - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false); - } - }); - } - }); - MessagesStorage.getInstance(currentAccount).putMessages(messagesArr, true, true, false, 0); - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - updateInterfaceWithMessages(-chat_id, pushMessages); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - }); - } - } - }); + AndroidUtilities.runOnUIThread(() -> { + final TLRPC.Chat chat = getChat(chat_id); + if (chat == null || !ChatObject.isChannel(chat_id, currentAccount) || chat.creator) { + return; } + TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); + req.channel = getInputChannel(chat_id); + req.user_id = new TLRPC.TL_inputUserSelf(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + final TLRPC.TL_channels_channelParticipant res = (TLRPC.TL_channels_channelParticipant) response; + if (res != null && res.participant instanceof TLRPC.TL_channelParticipantSelf && res.participant.inviter_id != UserConfig.getInstance(currentAccount).getClientUserId()) { + if (chat.megagroup && MessagesStorage.getInstance(currentAccount).isMigratedChat(chat.id)) { + return; + } + AndroidUtilities.runOnUIThread(() -> putUsers(res.users, false)); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); + + TLRPC.TL_messageService message = new TLRPC.TL_messageService(); + message.media_unread = true; + message.unread = true; + message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.post = true; + if (chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + message.local_id = message.id = UserConfig.getInstance(currentAccount).getNewMessageId(); + message.date = res.participant.date; + message.action = new TLRPC.TL_messageActionChatAddUser(); + message.from_id = res.participant.inviter_id; + message.action.users.add(UserConfig.getInstance(currentAccount).getClientUserId()); + message.to_id = new TLRPC.TL_peerChannel(); + message.to_id.channel_id = chat_id; + message.dialog_id = -chat_id; + UserConfig.getInstance(currentAccount).saveConfig(false); + + final ArrayList pushMessages = new ArrayList<>(); + final ArrayList messagesArr = new ArrayList<>(); + + ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + + messagesArr.add(message); + MessageObject obj = new MessageObject(currentAccount, message, usersDict, true); + pushMessages.add(obj); + + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(pushMessages, true, false))); + MessagesStorage.getInstance(currentAccount).putMessages(messagesArr, true, true, false, 0); + + AndroidUtilities.runOnUIThread(() -> { + updateInterfaceWithMessages(-chat_id, pushMessages); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + }); + } + }); }); } @@ -7937,45 +7204,29 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (printUpdate) { updatePrintingStrings(); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (printUpdate) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); - } - updateInterfaceWithMessages(user_id, objArr); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + AndroidUtilities.runOnUIThread(() -> { + if (printUpdate) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); } + updateInterfaceWithMessages(user_id, objArr); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); }); } else { final boolean printUpdate = updatePrintingUsersWithNewMessages(-updates.chat_id, objArr); if (printUpdate) { updatePrintingStrings(); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (printUpdate) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); - } - - updateInterfaceWithMessages(-updates.chat_id, objArr); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + AndroidUtilities.runOnUIThread(() -> { + if (printUpdate) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); } + + updateInterfaceWithMessages(-updates.chat_id, objArr); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); }); } if (!obj.isOut()) { - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(objArr, true, false); - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(objArr, true, false))); } MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0); } else if (MessagesStorage.getInstance(currentAccount).getLastPtsValue() != updates.pts) { @@ -8290,20 +7541,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (needReceivedQueue) { TLRPC.TL_messages_receivedQueue req = new TLRPC.TL_messages_receivedQueue(); req.max_qts = MessagesStorage.getInstance(currentAccount).getLastQtsValue(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } if (updateStatus) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS)); } MessagesStorage.getInstance(currentAccount).saveDiffParams(MessagesStorage.getInstance(currentAccount).getLastSeqValue(), MessagesStorage.getInstance(currentAccount).getLastPtsValue(), MessagesStorage.getInstance(currentAccount).getLastDateValue(), MessagesStorage.getInstance(currentAccount).getLastQtsValue()); } @@ -8311,12 +7554,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter public boolean processUpdateArray(ArrayList updates, final ArrayList usersArr, final ArrayList chatsArr, boolean fromGetDifference) { if (updates.isEmpty()) { if (usersArr != null || chatsArr != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(usersArr, false); - putChats(chatsArr, false); - } + AndroidUtilities.runOnUIThread(() -> { + putUsers(usersArr, false); + putChats(chatsArr, false); }); } return true; @@ -8369,12 +7609,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (usersArr != null || chatsArr != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(usersArr, false); - putChats(chatsArr, false); - } + AndroidUtilities.runOnUIThread(() -> { + putUsers(usersArr, false); + putChats(chatsArr, false); }); } @@ -8829,30 +8066,22 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (baseUpdate instanceof TLRPC.TL_updateUserBlocked) { final TLRPC.TL_updateUserBlocked finalUpdate = (TLRPC.TL_updateUserBlocked) baseUpdate; if (finalUpdate.blocked) { - ArrayList ids = new ArrayList<>(); - ids.add(finalUpdate.user_id); + SparseIntArray ids = new SparseIntArray(); + ids.put(finalUpdate.user_id, 1); MessagesStorage.getInstance(currentAccount).putBlockedUsers(ids, false); } else { MessagesStorage.getInstance(currentAccount).deleteBlockedUser(finalUpdate.user_id); } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (finalUpdate.blocked) { - if (!blockedUsers.contains(finalUpdate.user_id)) { - blockedUsers.add(finalUpdate.user_id); - } - } else { - blockedUsers.remove((Integer) finalUpdate.user_id); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + if (finalUpdate.blocked) { + if (blockedUsers.indexOfKey(finalUpdate.user_id) < 0) { + blockedUsers.put(finalUpdate.user_id, 1); + } + } else { + blockedUsers.delete(finalUpdate.user_id); } - }); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.blockedUsersDidLoaded); + })); } else if (baseUpdate instanceof TLRPC.TL_updateNotifySettings) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -8861,12 +8090,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (baseUpdate instanceof TLRPC.TL_updateServiceNotification) { final TLRPC.TL_updateServiceNotification update = (TLRPC.TL_updateServiceNotification) baseUpdate; if (update.popup && update.message != null && update.message.length() > 0) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 2, update.message, update.type); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 2, update.message, update.type)); } if ((update.flags & 2) != 0) { TLRPC.TL_message newMessage = new TLRPC.TL_message(); @@ -9230,17 +8454,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (pushMessages != null) { final ArrayList pushMessagesFinal = pushMessages; - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processNewMessages(pushMessagesFinal, true, false); - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processNewMessages(pushMessagesFinal, true, false))); } if (messagesArr != null) { @@ -9269,487 +8483,471 @@ public class MessagesController implements NotificationCenter.NotificationCenter final ArrayList chatInfoToUpdateFinal = chatInfoToUpdate; final ArrayList contactsIdsFinal = contactsIds; final ArrayList updatesOnMainThreadFinal = updatesOnMainThread; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - int updateMask = interfaceUpdateMaskFinal; - boolean hasDraftUpdates = false; + AndroidUtilities.runOnUIThread(() -> { + int updateMask = interfaceUpdateMaskFinal; + boolean hasDraftUpdates = false; - if (updatesOnMainThreadFinal != null) { - ArrayList dbUsers = new ArrayList<>(); - ArrayList dbUsersStatus = new ArrayList<>(); - SharedPreferences.Editor editor = null; - for (int a = 0, size = updatesOnMainThreadFinal.size(); a < size; a++) { - final TLRPC.Update baseUpdate = updatesOnMainThreadFinal.get(a); - if (baseUpdate instanceof TLRPC.TL_updatePrivacy) { - TLRPC.TL_updatePrivacy update = (TLRPC.TL_updatePrivacy) baseUpdate; - if (update.key instanceof TLRPC.TL_privacyKeyStatusTimestamp) { - ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 0); - } else if (update.key instanceof TLRPC.TL_privacyKeyChatInvite) { - ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 1); - } else if (update.key instanceof TLRPC.TL_privacyKeyPhoneCall) { - ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 2); - } - } else if (baseUpdate instanceof TLRPC.TL_updateUserStatus) { - TLRPC.TL_updateUserStatus update = (TLRPC.TL_updateUserStatus) baseUpdate; - final TLRPC.User currentUser = getUser(update.user_id); + if (updatesOnMainThreadFinal != null) { + ArrayList dbUsers = new ArrayList<>(); + ArrayList dbUsersStatus = new ArrayList<>(); + SharedPreferences.Editor editor = null; + for (int a = 0, size = updatesOnMainThreadFinal.size(); a < size; a++) { + final TLRPC.Update baseUpdate = updatesOnMainThreadFinal.get(a); + if (baseUpdate instanceof TLRPC.TL_updatePrivacy) { + TLRPC.TL_updatePrivacy update = (TLRPC.TL_updatePrivacy) baseUpdate; + if (update.key instanceof TLRPC.TL_privacyKeyStatusTimestamp) { + ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 0); + } else if (update.key instanceof TLRPC.TL_privacyKeyChatInvite) { + ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 1); + } else if (update.key instanceof TLRPC.TL_privacyKeyPhoneCall) { + ContactsController.getInstance(currentAccount).setPrivacyRules(update.rules, 2); + } + } else if (baseUpdate instanceof TLRPC.TL_updateUserStatus) { + TLRPC.TL_updateUserStatus update = (TLRPC.TL_updateUserStatus) baseUpdate; + final TLRPC.User currentUser = getUser(update.user_id); - if (update.status instanceof TLRPC.TL_userStatusRecently) { - update.status.expires = -100; - } else if (update.status instanceof TLRPC.TL_userStatusLastWeek) { - update.status.expires = -101; - } else if (update.status instanceof TLRPC.TL_userStatusLastMonth) { - update.status.expires = -102; + if (update.status instanceof TLRPC.TL_userStatusRecently) { + update.status.expires = -100; + } else if (update.status instanceof TLRPC.TL_userStatusLastWeek) { + update.status.expires = -101; + } else if (update.status instanceof TLRPC.TL_userStatusLastMonth) { + update.status.expires = -102; + } + if (currentUser != null) { + currentUser.id = update.user_id; + currentUser.status = update.status; + } + final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove + toDbUser.id = update.user_id; + toDbUser.status = update.status; + dbUsersStatus.add(toDbUser); + if (update.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { + NotificationsController.getInstance(currentAccount).setLastOnlineFromOtherDevice(update.status.expires); + } + } else if (baseUpdate instanceof TLRPC.TL_updateUserName) { + TLRPC.TL_updateUserName update = (TLRPC.TL_updateUserName) baseUpdate; + final TLRPC.User currentUser = getUser(update.user_id); + if (currentUser != null) { + if (!UserObject.isContact(currentUser)) { + currentUser.first_name = update.first_name; + currentUser.last_name = update.last_name; } - if (currentUser != null) { - currentUser.id = update.user_id; - currentUser.status = update.status; + if (!TextUtils.isEmpty(currentUser.username)) { + objectsByUsernames.remove(currentUser.username); } - final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove - toDbUser.id = update.user_id; - toDbUser.status = update.status; - dbUsersStatus.add(toDbUser); - if (update.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - NotificationsController.getInstance(currentAccount).setLastOnlineFromOtherDevice(update.status.expires); + if (TextUtils.isEmpty(update.username)) { + objectsByUsernames.put(update.username, currentUser); } - } else if (baseUpdate instanceof TLRPC.TL_updateUserName) { - TLRPC.TL_updateUserName update = (TLRPC.TL_updateUserName) baseUpdate; - final TLRPC.User currentUser = getUser(update.user_id); - if (currentUser != null) { - if (!UserObject.isContact(currentUser)) { - currentUser.first_name = update.first_name; - currentUser.last_name = update.last_name; - } - if (!TextUtils.isEmpty(currentUser.username)) { - objectsByUsernames.remove(currentUser.username); - } - if (TextUtils.isEmpty(update.username)) { - objectsByUsernames.put(update.username, currentUser); - } - currentUser.username = update.username; - } - final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove - toDbUser.id = update.user_id; - toDbUser.first_name = update.first_name; - toDbUser.last_name = update.last_name; - toDbUser.username = update.username; - dbUsers.add(toDbUser); - } else if (baseUpdate instanceof TLRPC.TL_updateDialogPinned) { - TLRPC.TL_updateDialogPinned updateDialogPinned = (TLRPC.TL_updateDialogPinned) baseUpdate; - long did; - if (updateDialogPinned.peer instanceof TLRPC.TL_dialogPeer) { - TLRPC.Peer peer = ((TLRPC.TL_dialogPeer) updateDialogPinned.peer).peer; - if (peer instanceof TLRPC.TL_peerUser) { - did = peer.user_id; - } else if (peer instanceof TLRPC.TL_peerChat) { - did = -peer.chat_id; - } else { - did = -peer.channel_id; - } + currentUser.username = update.username; + } + final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove + toDbUser.id = update.user_id; + toDbUser.first_name = update.first_name; + toDbUser.last_name = update.last_name; + toDbUser.username = update.username; + dbUsers.add(toDbUser); + } else if (baseUpdate instanceof TLRPC.TL_updateDialogPinned) { + TLRPC.TL_updateDialogPinned updateDialogPinned = (TLRPC.TL_updateDialogPinned) baseUpdate; + long did; + if (updateDialogPinned.peer instanceof TLRPC.TL_dialogPeer) { + TLRPC.Peer peer = ((TLRPC.TL_dialogPeer) updateDialogPinned.peer).peer; + if (peer instanceof TLRPC.TL_peerUser) { + did = peer.user_id; + } else if (peer instanceof TLRPC.TL_peerChat) { + did = -peer.chat_id; } else { - did = 0; + did = -peer.channel_id; } - if (!pinDialog(did, updateDialogPinned.pinned, null, -1)) { - UserConfig.getInstance(currentAccount).pinnedDialogsLoaded = false; - UserConfig.getInstance(currentAccount).saveConfig(false); - loadPinnedDialogs(did, null); - } - } else if (baseUpdate instanceof TLRPC.TL_updatePinnedDialogs) { - TLRPC.TL_updatePinnedDialogs update = (TLRPC.TL_updatePinnedDialogs) baseUpdate; + } else { + did = 0; + } + if (!pinDialog(did, updateDialogPinned.pinned, null, -1)) { UserConfig.getInstance(currentAccount).pinnedDialogsLoaded = false; UserConfig.getInstance(currentAccount).saveConfig(false); - ArrayList order; - if ((update.flags & 1) != 0) { - order = new ArrayList<>(); - ArrayList peers = ((TLRPC.TL_updatePinnedDialogs) baseUpdate).order; - for (int b = 0, size2 = peers.size(); b < size2; b++) { - long did; - TLRPC.DialogPeer dialogPeer = peers.get(b); - if (dialogPeer instanceof TLRPC.TL_dialogPeer) { - TLRPC.Peer peer = ((TLRPC.TL_dialogPeer) dialogPeer).peer; - if (peer.user_id != 0) { - did = peer.user_id; - } else if (peer.chat_id != 0) { - did = -peer.chat_id; - } else { - did = -peer.channel_id; - } + loadPinnedDialogs(did, null); + } + } else if (baseUpdate instanceof TLRPC.TL_updatePinnedDialogs) { + TLRPC.TL_updatePinnedDialogs update = (TLRPC.TL_updatePinnedDialogs) baseUpdate; + UserConfig.getInstance(currentAccount).pinnedDialogsLoaded = false; + UserConfig.getInstance(currentAccount).saveConfig(false); + ArrayList order; + if ((update.flags & 1) != 0) { + order = new ArrayList<>(); + ArrayList peers = ((TLRPC.TL_updatePinnedDialogs) baseUpdate).order; + for (int b = 0, size2 = peers.size(); b < size2; b++) { + long did; + TLRPC.DialogPeer dialogPeer = peers.get(b); + if (dialogPeer instanceof TLRPC.TL_dialogPeer) { + TLRPC.Peer peer = ((TLRPC.TL_dialogPeer) dialogPeer).peer; + if (peer.user_id != 0) { + did = peer.user_id; + } else if (peer.chat_id != 0) { + did = -peer.chat_id; } else { - did = 0; + did = -peer.channel_id; } - order.add(did); + } else { + did = 0; } - } else { - order = null; + order.add(did); } - loadPinnedDialogs(0, order); - } else if (baseUpdate instanceof TLRPC.TL_updateUserPhoto) { - TLRPC.TL_updateUserPhoto update = (TLRPC.TL_updateUserPhoto) baseUpdate; - final TLRPC.User currentUser = getUser(update.user_id); - if (currentUser != null) { - currentUser.photo = update.photo; + } else { + order = null; + } + loadPinnedDialogs(0, order); + } else if (baseUpdate instanceof TLRPC.TL_updateUserPhoto) { + TLRPC.TL_updateUserPhoto update = (TLRPC.TL_updateUserPhoto) baseUpdate; + final TLRPC.User currentUser = getUser(update.user_id); + if (currentUser != null) { + currentUser.photo = update.photo; + } + final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove + toDbUser.id = update.user_id; + toDbUser.photo = update.photo; + dbUsers.add(toDbUser); + } else if (baseUpdate instanceof TLRPC.TL_updateUserPhone) { + TLRPC.TL_updateUserPhone update = (TLRPC.TL_updateUserPhone) baseUpdate; + final TLRPC.User currentUser = getUser(update.user_id); + if (currentUser != null) { + currentUser.phone = update.phone; + Utilities.phoneBookQueue.postRunnable(() -> ContactsController.getInstance(currentAccount).addContactToPhoneBook(currentUser, true)); + } + final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove + toDbUser.id = update.user_id; + toDbUser.phone = update.phone; + dbUsers.add(toDbUser); + } else if (baseUpdate instanceof TLRPC.TL_updateNotifySettings) { + TLRPC.TL_updateNotifySettings update = (TLRPC.TL_updateNotifySettings) baseUpdate; + if (update.notify_settings instanceof TLRPC.TL_peerNotifySettings) { + if (editor == null) { + editor = notificationsPreferences.edit(); } - final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove - toDbUser.id = update.user_id; - toDbUser.photo = update.photo; - dbUsers.add(toDbUser); - } else if (baseUpdate instanceof TLRPC.TL_updateUserPhone) { - TLRPC.TL_updateUserPhone update = (TLRPC.TL_updateUserPhone) baseUpdate; - final TLRPC.User currentUser = getUser(update.user_id); - if (currentUser != null) { - currentUser.phone = update.phone; - Utilities.phoneBookQueue.postRunnable(new Runnable() { - @Override - public void run() { - ContactsController.getInstance(currentAccount).addContactToPhoneBook(currentUser, true); - } - }); - } - final TLRPC.User toDbUser = new TLRPC.TL_user(); //TODO remove - toDbUser.id = update.user_id; - toDbUser.phone = update.phone; - dbUsers.add(toDbUser); - } else if (baseUpdate instanceof TLRPC.TL_updateNotifySettings) { - TLRPC.TL_updateNotifySettings update = (TLRPC.TL_updateNotifySettings) baseUpdate; - if (update.notify_settings instanceof TLRPC.TL_peerNotifySettings) { - if (editor == null) { - editor = notificationsPreferences.edit(); + int currentTime1 = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + if (update.peer instanceof TLRPC.TL_notifyPeer) { + long dialog_id; + if (update.peer.peer.user_id != 0) { + dialog_id = update.peer.peer.user_id; + } else if (update.peer.peer.chat_id != 0) { + dialog_id = -update.peer.peer.chat_id; + } else { + dialog_id = -update.peer.peer.channel_id; } - int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - if (update.peer instanceof TLRPC.TL_notifyPeer) { - long dialog_id; - if (update.peer.peer.user_id != 0) { - dialog_id = update.peer.peer.user_id; - } else if (update.peer.peer.chat_id != 0) { - dialog_id = -update.peer.peer.chat_id; - } else { - dialog_id = -update.peer.peer.channel_id; - } - TLRPC.TL_dialog dialog = dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = update.notify_settings; - } - if ((update.notify_settings.flags & 2) != 0) { - editor.putBoolean("silent_" + dialog_id, update.notify_settings.silent); - } else { - editor.remove("silent_" + dialog_id); - } - if ((update.notify_settings.flags & 4) != 0) { - if (update.notify_settings.mute_until > currentTime) { - int until = 0; - if (update.notify_settings.mute_until > currentTime + 60 * 60 * 24 * 365) { - editor.putInt("notify2_" + dialog_id, 2); - if (dialog != null) { - update.notify_settings.mute_until = Integer.MAX_VALUE; - } - } else { - until = update.notify_settings.mute_until; - editor.putInt("notify2_" + dialog_id, 3); - editor.putInt("notifyuntil_" + dialog_id, update.notify_settings.mute_until); - if (dialog != null) { - update.notify_settings.mute_until = until; - } - } - MessagesStorage.getInstance(currentAccount).setDialogFlags(dialog_id, ((long) until << 32) | 1); - NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(dialog_id); - } else { + TLRPC.TL_dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = update.notify_settings; + } + if ((update.notify_settings.flags & 2) != 0) { + editor.putBoolean("silent_" + dialog_id, update.notify_settings.silent); + } else { + editor.remove("silent_" + dialog_id); + } + if ((update.notify_settings.flags & 4) != 0) { + if (update.notify_settings.mute_until > currentTime1) { + int until = 0; + if (update.notify_settings.mute_until > currentTime1 + 60 * 60 * 24 * 365) { + editor.putInt("notify2_" + dialog_id, 2); if (dialog != null) { - update.notify_settings.mute_until = 0; + update.notify_settings.mute_until = Integer.MAX_VALUE; + } + } else { + until = update.notify_settings.mute_until; + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, update.notify_settings.mute_until); + if (dialog != null) { + update.notify_settings.mute_until = until; } - editor.putInt("notify2_" + dialog_id, 0); - MessagesStorage.getInstance(currentAccount).setDialogFlags(dialog_id, 0); } + MessagesStorage.getInstance(currentAccount).setDialogFlags(dialog_id, ((long) until << 32) | 1); + NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(dialog_id); } else { if (dialog != null) { update.notify_settings.mute_until = 0; } - editor.remove("notify2_" + dialog_id); + editor.putInt("notify2_" + dialog_id, 0); MessagesStorage.getInstance(currentAccount).setDialogFlags(dialog_id, 0); } - } else if (update.peer instanceof TLRPC.TL_notifyChats) { - if ((update.notify_settings.flags & 1) != 0) { - editor.putBoolean("EnablePreviewGroup", update.notify_settings.show_previews); - } - if ((update.notify_settings.flags & 2) != 0) { - /*if (update.notify_settings.silent) { - editor.putString("GroupSoundPath", "NoSound"); - } else { - editor.remove("GroupSoundPath"); - }*/ - } - if ((update.notify_settings.flags & 4) != 0) { - editor.putBoolean("EnableGroup", update.notify_settings.mute_until < currentTime); - } - } else if (update.peer instanceof TLRPC.TL_notifyUsers) { - if ((update.notify_settings.flags & 1) != 0) { - editor.putBoolean("EnablePreviewAll", update.notify_settings.show_previews); - } - if ((update.notify_settings.flags & 2) != 0) { - /*if (update.notify_settings.silent) { - editor.putString("GlobalSoundPath", "NoSound"); - } else { - editor.remove("GlobalSoundPath"); - }*/ - } - if ((update.notify_settings.flags & 4) != 0) { - editor.putBoolean("EnableAll", update.notify_settings.mute_until < currentTime); - } - } - } - } else if (baseUpdate instanceof TLRPC.TL_updateChannel) { - final TLRPC.TL_updateChannel update = (TLRPC.TL_updateChannel) baseUpdate; - TLRPC.TL_dialog dialog = dialogs_dict.get(-(long) update.channel_id); - TLRPC.Chat chat = getChat(update.channel_id); - if (chat != null) { - if (dialog == null && chat instanceof TLRPC.TL_channel && !chat.left) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - getChannelDifference(update.channel_id, 1, 0, null); - } - }); - } else if (chat.left && dialog != null && (proxyDialog == null || proxyDialog.id != dialog.id)) { - deleteDialog(dialog.id, 0); - } - } - updateMask |= UPDATE_MASK_CHANNEL; - loadFullChat(update.channel_id, 0, true); - } else if (baseUpdate instanceof TLRPC.TL_updateChatAdmins) { - updateMask |= UPDATE_MASK_CHAT_ADMINS; - } else if (baseUpdate instanceof TLRPC.TL_updateStickerSets) { - TLRPC.TL_updateStickerSets update = (TLRPC.TL_updateStickerSets) baseUpdate; - DataQuery.getInstance(currentAccount).loadStickers(DataQuery.TYPE_IMAGE, false, true); - } else if (baseUpdate instanceof TLRPC.TL_updateStickerSetsOrder) { - TLRPC.TL_updateStickerSetsOrder update = (TLRPC.TL_updateStickerSetsOrder) baseUpdate; - DataQuery.getInstance(currentAccount).reorderStickers(update.masks ? DataQuery.TYPE_MASK : DataQuery.TYPE_IMAGE, ((TLRPC.TL_updateStickerSetsOrder) baseUpdate).order); - } else if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { - DataQuery.getInstance(currentAccount).loadRecents(DataQuery.TYPE_FAVE, false, false, true); - } else if (baseUpdate instanceof TLRPC.TL_updateContactsReset) { - ContactsController.getInstance(currentAccount).forceImportContacts(); - } else if (baseUpdate instanceof TLRPC.TL_updateNewStickerSet) { - TLRPC.TL_updateNewStickerSet update = (TLRPC.TL_updateNewStickerSet) baseUpdate; - DataQuery.getInstance(currentAccount).addNewStickerSet(update.stickerset); - } else if (baseUpdate instanceof TLRPC.TL_updateSavedGifs) { - SharedPreferences.Editor editor2 = emojiPreferences.edit(); - editor2.putLong("lastGifLoadTime", 0).commit(); - } else if (baseUpdate instanceof TLRPC.TL_updateRecentStickers) { - SharedPreferences.Editor editor2 = emojiPreferences.edit(); - editor2.putLong("lastStickersLoadTime", 0).commit(); - } else if (baseUpdate instanceof TLRPC.TL_updateDraftMessage) { - TLRPC.TL_updateDraftMessage update = (TLRPC.TL_updateDraftMessage) baseUpdate; - hasDraftUpdates = true; - long did; - TLRPC.Peer peer = ((TLRPC.TL_updateDraftMessage) baseUpdate).peer; - if (peer.user_id != 0) { - did = peer.user_id; - } else if (peer.channel_id != 0) { - did = -peer.channel_id; - } else { - did = -peer.chat_id; - } - DataQuery.getInstance(currentAccount).saveDraft(did, update.draft, null, true); - } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers) { - DataQuery.getInstance(currentAccount).markFaturedStickersAsRead(false); - } else if (baseUpdate instanceof TLRPC.TL_updatePhoneCall) { - TLRPC.TL_updatePhoneCall upd = (TLRPC.TL_updatePhoneCall) baseUpdate; - TLRPC.PhoneCall call = upd.phone_call; - VoIPService svc = VoIPService.getSharedInstance(); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("Received call in update: " + call); - FileLog.d("call id " + call.id); - } - if (call instanceof TLRPC.TL_phoneCallRequested) { - if (call.date + callRingTimeout / 1000 < ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("ignoring too old call"); - } - continue; - } - TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); - if (svc != null || VoIPService.callIShouldHavePutIntoIntent!=null || tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("Auto-declining call " + call.id + " because there's already active one"); - } - TLRPC.TL_phone_discardCall req = new TLRPC.TL_phone_discardCall(); - req.peer = new TLRPC.TL_inputPhoneCall(); - req.peer.access_hash = call.access_hash; - req.peer.id = call.id; - req.reason = new TLRPC.TL_phoneCallDiscardReasonBusy(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - TLRPC.Updates updates = (TLRPC.Updates) response; - processUpdates(updates, false); - } - } - }); - continue; - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("Starting service for call " + call.id); - } - VoIPService.callIShouldHavePutIntoIntent = call; - Intent intent = new Intent(ApplicationLoader.applicationContext, VoIPService.class); - intent.putExtra("is_outgoing", false); - intent.putExtra("user_id", call.participant_id == UserConfig.getInstance(currentAccount).getClientUserId() ? call.admin_id : call.participant_id); - intent.putExtra("account", currentAccount); - try { - if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ - ApplicationLoader.applicationContext.startForegroundService(intent); - }else{ - ApplicationLoader.applicationContext.startService(intent); - } - } catch (Throwable e) { - FileLog.e(e); - } - } else { - if (svc != null && call != null) { - svc.onCallUpdated(call); - } else if (VoIPService.callIShouldHavePutIntoIntent != null) { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("Updated the call while the service is starting"); - } - if (call.id == VoIPService.callIShouldHavePutIntoIntent.id) { - VoIPService.callIShouldHavePutIntoIntent = call; - } - } - } - } else if (baseUpdate instanceof TLRPC.TL_updateDialogUnreadMark) { - TLRPC.TL_updateDialogUnreadMark update = (TLRPC.TL_updateDialogUnreadMark) baseUpdate; - long did; - if (update.peer instanceof TLRPC.TL_dialogPeer) { - TLRPC.TL_dialogPeer dialogPeer = (TLRPC.TL_dialogPeer) update.peer; - if (dialogPeer.peer.user_id != 0) { - did = dialogPeer.peer.user_id; - } else if (dialogPeer.peer.chat_id != 0) { - did = -dialogPeer.peer.chat_id; } else { - did = -dialogPeer.peer.channel_id; + if (dialog != null) { + update.notify_settings.mute_until = 0; + } + editor.remove("notify2_" + dialog_id); + MessagesStorage.getInstance(currentAccount).setDialogFlags(dialog_id, 0); } - } else { - did = 0; - } - MessagesStorage.getInstance(currentAccount).setDialogUnread(did, update.unread); - TLRPC.TL_dialog dialog = dialogs_dict.get(did); - if (dialog != null && dialog.unread_mark != update.unread) { - dialog.unread_mark = update.unread; - if (dialog.unread_count == 0 && !isDialogMuted(did)) { - if (dialog.unread_mark) { - unreadUnmutedDialogs++; + } else if (update.peer instanceof TLRPC.TL_notifyChats) { + if ((update.notify_settings.flags & 1) != 0) { + editor.putBoolean("EnablePreviewGroup", update.notify_settings.show_previews); + } + if ((update.notify_settings.flags & 2) != 0) { + /*if (update.notify_settings.silent) { + editor.putString("GroupSoundPath", "NoSound"); } else { - unreadUnmutedDialogs--; - } + editor.remove("GroupSoundPath"); + }*/ + } + if ((update.notify_settings.flags & 4) != 0) { + editor.putBoolean("EnableGroup", update.notify_settings.mute_until < currentTime1); + } + } else if (update.peer instanceof TLRPC.TL_notifyUsers) { + if ((update.notify_settings.flags & 1) != 0) { + editor.putBoolean("EnablePreviewAll", update.notify_settings.show_previews); + } + if ((update.notify_settings.flags & 2) != 0) { + /*if (update.notify_settings.silent) { + editor.putString("GlobalSoundPath", "NoSound"); + } else { + editor.remove("GlobalSoundPath"); + }*/ + } + if ((update.notify_settings.flags & 4) != 0) { + editor.putBoolean("EnableAll", update.notify_settings.mute_until < currentTime1); } - updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; } - } else if (baseUpdate instanceof TLRPC.TL_updateGroupCall) { - - } else if (baseUpdate instanceof TLRPC.TL_updateGroupCallParticipant) { - } - } - if (editor != null) { - editor.commit(); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.notificationsSettingsUpdated); - } - MessagesStorage.getInstance(currentAccount).updateUsers(dbUsersStatus, true, true, true); - MessagesStorage.getInstance(currentAccount).updateUsers(dbUsers, false, true, true); - } - - if (webPagesFinal != null) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didReceivedWebpagesInUpdates, webPagesFinal); - for (int b = 0, size = webPagesFinal.size(); b < size; b++) { - long key = webPagesFinal.keyAt(b); - ArrayList arrayList = reloadingWebpagesPending.get(key); - reloadingWebpagesPending.remove(key); - if (arrayList != null) { - TLRPC.WebPage webpage = webPagesFinal.valueAt(b); - ArrayList arr = new ArrayList<>(); - long dialog_id = 0; - if (webpage instanceof TLRPC.TL_webPage || webpage instanceof TLRPC.TL_webPageEmpty) { - for (int a = 0, size2 = arrayList.size(); a < size2; a++) { - arrayList.get(a).messageOwner.media.webpage = webpage; - if (a == 0) { - dialog_id = arrayList.get(a).getDialogId(); - ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); - } - arr.add(arrayList.get(a).messageOwner); + } else if (baseUpdate instanceof TLRPC.TL_updateChannel) { + final TLRPC.TL_updateChannel update = (TLRPC.TL_updateChannel) baseUpdate; + TLRPC.TL_dialog dialog = dialogs_dict.get(-(long) update.channel_id); + TLRPC.Chat chat = getChat(update.channel_id); + if (chat != null) { + if (dialog == null && chat instanceof TLRPC.TL_channel && !chat.left) { + Utilities.stageQueue.postRunnable(() -> getChannelDifference(update.channel_id, 1, 0, null)); + } else if (chat.left && dialog != null && (proxyDialog == null || proxyDialog.id != dialog.id)) { + deleteDialog(dialog.id, 0); + } + } + updateMask |= UPDATE_MASK_CHANNEL; + loadFullChat(update.channel_id, 0, true); + } else if (baseUpdate instanceof TLRPC.TL_updateChatAdmins) { + updateMask |= UPDATE_MASK_CHAT_ADMINS; + } else if (baseUpdate instanceof TLRPC.TL_updateStickerSets) { + TLRPC.TL_updateStickerSets update = (TLRPC.TL_updateStickerSets) baseUpdate; + DataQuery.getInstance(currentAccount).loadStickers(DataQuery.TYPE_IMAGE, false, true); + } else if (baseUpdate instanceof TLRPC.TL_updateStickerSetsOrder) { + TLRPC.TL_updateStickerSetsOrder update = (TLRPC.TL_updateStickerSetsOrder) baseUpdate; + DataQuery.getInstance(currentAccount).reorderStickers(update.masks ? DataQuery.TYPE_MASK : DataQuery.TYPE_IMAGE, ((TLRPC.TL_updateStickerSetsOrder) baseUpdate).order); + } else if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { + DataQuery.getInstance(currentAccount).loadRecents(DataQuery.TYPE_FAVE, false, false, true); + } else if (baseUpdate instanceof TLRPC.TL_updateContactsReset) { + ContactsController.getInstance(currentAccount).forceImportContacts(); + } else if (baseUpdate instanceof TLRPC.TL_updateNewStickerSet) { + TLRPC.TL_updateNewStickerSet update = (TLRPC.TL_updateNewStickerSet) baseUpdate; + DataQuery.getInstance(currentAccount).addNewStickerSet(update.stickerset); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedGifs) { + SharedPreferences.Editor editor2 = emojiPreferences.edit(); + editor2.putLong("lastGifLoadTime", 0).commit(); + } else if (baseUpdate instanceof TLRPC.TL_updateRecentStickers) { + SharedPreferences.Editor editor2 = emojiPreferences.edit(); + editor2.putLong("lastStickersLoadTime", 0).commit(); + } else if (baseUpdate instanceof TLRPC.TL_updateDraftMessage) { + TLRPC.TL_updateDraftMessage update = (TLRPC.TL_updateDraftMessage) baseUpdate; + hasDraftUpdates = true; + long did; + TLRPC.Peer peer = ((TLRPC.TL_updateDraftMessage) baseUpdate).peer; + if (peer.user_id != 0) { + did = peer.user_id; + } else if (peer.channel_id != 0) { + did = -peer.channel_id; + } else { + did = -peer.chat_id; + } + DataQuery.getInstance(currentAccount).saveDraft(did, update.draft, null, true); + } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers) { + DataQuery.getInstance(currentAccount).markFaturedStickersAsRead(false); + } else if (baseUpdate instanceof TLRPC.TL_updatePhoneCall) { + TLRPC.TL_updatePhoneCall upd = (TLRPC.TL_updatePhoneCall) baseUpdate; + TLRPC.PhoneCall call = upd.phone_call; + VoIPService svc = VoIPService.getSharedInstance(); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Received call in update: " + call); + FileLog.d("call id " + call.id); + } + if (call instanceof TLRPC.TL_phoneCallRequested) { + if (call.date + callRingTimeout / 1000 < ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("ignoring too old call"); } + continue; + } + TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + if (svc != null || VoIPService.callIShouldHavePutIntoIntent!=null || tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Auto-declining call " + call.id + " because there's already active one"); + } + TLRPC.TL_phone_discardCall req = new TLRPC.TL_phone_discardCall(); + req.peer = new TLRPC.TL_inputPhoneCall(); + req.peer.access_hash = call.access_hash; + req.peer.id = call.id; + req.reason = new TLRPC.TL_phoneCallDiscardReasonBusy(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.Updates updates1 = (TLRPC.Updates) response; + processUpdates(updates1, false); + } + }); + continue; + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Starting service for call " + call.id); + } + VoIPService.callIShouldHavePutIntoIntent = call; + Intent intent = new Intent(ApplicationLoader.applicationContext, VoIPService.class); + intent.putExtra("is_outgoing", false); + intent.putExtra("user_id", call.participant_id == UserConfig.getInstance(currentAccount).getClientUserId() ? call.admin_id : call.participant_id); + intent.putExtra("account", currentAccount); + try { + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ + ApplicationLoader.applicationContext.startForegroundService(intent); + }else{ + ApplicationLoader.applicationContext.startService(intent); + } + } catch (Throwable e) { + FileLog.e(e); + } + } else { + if (svc != null && call != null) { + svc.onCallUpdated(call); + } else if (VoIPService.callIShouldHavePutIntoIntent != null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Updated the call while the service is starting"); + } + if (call.id == VoIPService.callIShouldHavePutIntoIntent.id) { + VoIPService.callIShouldHavePutIntoIntent = call; + } + } + } + } else if (baseUpdate instanceof TLRPC.TL_updateDialogUnreadMark) { + TLRPC.TL_updateDialogUnreadMark update = (TLRPC.TL_updateDialogUnreadMark) baseUpdate; + long did; + if (update.peer instanceof TLRPC.TL_dialogPeer) { + TLRPC.TL_dialogPeer dialogPeer = (TLRPC.TL_dialogPeer) update.peer; + if (dialogPeer.peer.user_id != 0) { + did = dialogPeer.peer.user_id; + } else if (dialogPeer.peer.chat_id != 0) { + did = -dialogPeer.peer.chat_id; } else { - reloadingWebpagesPending.put(webpage.id, arrayList); - } - if (!arr.isEmpty()) { - MessagesStorage.getInstance(currentAccount).putMessages(arr, true, true, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + did = -dialogPeer.peer.channel_id; } + } else { + did = 0; } - } - } - - boolean updateDialogs = false; - if (messagesFinal != null) { - for (int a = 0, size = messagesFinal.size(); a < size; a++) { - long key = messagesFinal.keyAt(a); - ArrayList value = messagesFinal.valueAt(a); - updateInterfaceWithMessages(key, value); - } - updateDialogs = true; - } else if (hasDraftUpdates) { - sortDialogs(null); - updateDialogs = true; - } - if (editingMessagesFinal != null) { - for (int b = 0, size = editingMessagesFinal.size(); b < size; b++) { - long dialog_id = editingMessagesFinal.keyAt(b); - ArrayList arrayList = editingMessagesFinal.valueAt(b); - MessageObject oldObject = dialogMessage.get(dialog_id); - if (oldObject != null) { - for (int a = 0, size2 = arrayList.size(); a < size2; a++) { - MessageObject newMessage = arrayList.get(a); - if (oldObject.getId() == newMessage.getId()) { - dialogMessage.put(dialog_id, newMessage); - if (newMessage.messageOwner.to_id != null && newMessage.messageOwner.to_id.channel_id == 0) { - dialogMessagesByIds.put(newMessage.getId(), newMessage); - } - updateDialogs = true; - break; - } else if (oldObject.getDialogId() == newMessage.getDialogId() && oldObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage && oldObject.replyMessageObject != null && oldObject.replyMessageObject.getId() == newMessage.getId()) { - oldObject.replyMessageObject = newMessage; - oldObject.generatePinMessageText(null, null); - updateDialogs = true; - break; + MessagesStorage.getInstance(currentAccount).setDialogUnread(did, update.unread); + TLRPC.TL_dialog dialog = dialogs_dict.get(did); + if (dialog != null && dialog.unread_mark != update.unread) { + dialog.unread_mark = update.unread; + if (dialog.unread_count == 0 && !isDialogMuted(did)) { + if (dialog.unread_mark) { + unreadUnmutedDialogs++; + } else { + unreadUnmutedDialogs--; } } + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; } - DataQuery.getInstance(currentAccount).loadReplyMessagesForMessages(arrayList, dialog_id); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); - } - } - if (updateDialogs) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } + } else if (baseUpdate instanceof TLRPC.TL_updateGroupCall) { + + } else if (baseUpdate instanceof TLRPC.TL_updateGroupCallParticipant) { - if (printChangedArg) { - updateMask |= UPDATE_MASK_USER_PRINT; - } - if (contactsIdsFinal != null) { - updateMask |= UPDATE_MASK_NAME; - updateMask |= UPDATE_MASK_USER_PHONE; - } - if (chatInfoToUpdateFinal != null) { - for (int a = 0, size = chatInfoToUpdateFinal.size(); a < size; a++) { - TLRPC.ChatParticipants info = chatInfoToUpdateFinal.get(a); - MessagesStorage.getInstance(currentAccount).updateChatParticipants(info); } } - if (channelViewsFinal != null) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViewsFinal); + if (editor != null) { + editor.commit(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.notificationsSettingsUpdated); } - if (updateMask != 0) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, updateMask); + MessagesStorage.getInstance(currentAccount).updateUsers(dbUsersStatus, true, true, true); + MessagesStorage.getInstance(currentAccount).updateUsers(dbUsers, false, true, true); + } + + if (webPagesFinal != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didReceivedWebpagesInUpdates, webPagesFinal); + for (int b = 0, size = webPagesFinal.size(); b < size; b++) { + long key = webPagesFinal.keyAt(b); + ArrayList arrayList = reloadingWebpagesPending.get(key); + reloadingWebpagesPending.remove(key); + if (arrayList != null) { + TLRPC.WebPage webpage = webPagesFinal.valueAt(b); + ArrayList arr = new ArrayList<>(); + long dialog_id = 0; + if (webpage instanceof TLRPC.TL_webPage || webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0, size2 = arrayList.size(); a < size2; a++) { + arrayList.get(a).messageOwner.media.webpage = webpage; + if (a == 0) { + dialog_id = arrayList.get(a).getDialogId(); + ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); + } + arr.add(arrayList.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(webpage.id, arrayList); + } + if (!arr.isEmpty()) { + MessagesStorage.getInstance(currentAccount).putMessages(arr, true, true, false, DownloadController.getInstance(currentAccount).getAutodownloadMask()); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } } } + + boolean updateDialogs = false; + if (messagesFinal != null) { + for (int a = 0, size = messagesFinal.size(); a < size; a++) { + long key = messagesFinal.keyAt(a); + ArrayList value = messagesFinal.valueAt(a); + updateInterfaceWithMessages(key, value); + } + updateDialogs = true; + } else if (hasDraftUpdates) { + sortDialogs(null); + updateDialogs = true; + } + if (editingMessagesFinal != null) { + for (int b = 0, size = editingMessagesFinal.size(); b < size; b++) { + long dialog_id = editingMessagesFinal.keyAt(b); + ArrayList arrayList = editingMessagesFinal.valueAt(b); + MessageObject oldObject = dialogMessage.get(dialog_id); + if (oldObject != null) { + for (int a = 0, size2 = arrayList.size(); a < size2; a++) { + MessageObject newMessage = arrayList.get(a); + if (oldObject.getId() == newMessage.getId()) { + dialogMessage.put(dialog_id, newMessage); + if (newMessage.messageOwner.to_id != null && newMessage.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(newMessage.getId(), newMessage); + } + updateDialogs = true; + break; + } else if (oldObject.getDialogId() == newMessage.getDialogId() && oldObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage && oldObject.replyMessageObject != null && oldObject.replyMessageObject.getId() == newMessage.getId()) { + oldObject.replyMessageObject = newMessage; + oldObject.generatePinMessageText(null, null); + updateDialogs = true; + break; + } + } + } + DataQuery.getInstance(currentAccount).loadReplyMessagesForMessages(arrayList, dialog_id); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + if (updateDialogs) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + } + + if (printChangedArg) { + updateMask |= UPDATE_MASK_USER_PRINT; + } + if (contactsIdsFinal != null) { + updateMask |= UPDATE_MASK_NAME; + updateMask |= UPDATE_MASK_USER_PHONE; + } + if (chatInfoToUpdateFinal != null) { + for (int a = 0, size = chatInfoToUpdateFinal.size(); a < size; a++) { + TLRPC.ChatParticipants info = chatInfoToUpdateFinal.get(a); + MessagesStorage.getInstance(currentAccount).updateChatParticipants(info); + } + } + if (channelViewsFinal != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViewsFinal); + } + if (updateMask != 0) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, updateMask); + } }); final SparseLongArray markAsReadMessagesInboxFinal = markAsReadMessagesInbox; @@ -9758,123 +8956,115 @@ public class MessagesController implements NotificationCenter.NotificationCenter final SparseIntArray markAsReadEncryptedFinal = markAsReadEncrypted; final SparseArray> deletedMessagesFinal = deletedMessages; final SparseIntArray clearHistoryMessagesFinal = clearHistoryMessages; - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - int updateMask = 0; - if (markAsReadMessagesInboxFinal != null || markAsReadMessagesOutboxFinal != null) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesRead, markAsReadMessagesInboxFinal, markAsReadMessagesOutboxFinal); - if (markAsReadMessagesInboxFinal != null) { - NotificationsController.getInstance(currentAccount).processReadMessages(markAsReadMessagesInboxFinal, 0, 0, 0, false); - SharedPreferences.Editor editor = notificationsPreferences.edit(); - for (int b = 0, size = markAsReadMessagesInboxFinal.size(); b < size; b++) { - int key = markAsReadMessagesInboxFinal.keyAt(b); - int messageId = (int) markAsReadMessagesInboxFinal.valueAt(b); - TLRPC.TL_dialog dialog = dialogs_dict.get((long) key); - if (dialog != null && dialog.top_message > 0 && dialog.top_message <= messageId) { - MessageObject obj = dialogMessage.get(dialog.id); - if (obj != null && !obj.isOut()) { - obj.setIsRead(); - updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; - } - } - if (key != UserConfig.getInstance(currentAccount).getClientUserId()) { - editor.remove("diditem" + key); - editor.remove("diditemo" + key); - } - } - editor.commit(); - } - if (markAsReadMessagesOutboxFinal != null) { - for (int b = 0, size = markAsReadMessagesOutboxFinal.size(); b < size; b++) { - int key = markAsReadMessagesOutboxFinal.keyAt(b); - int messageId = (int) markAsReadMessagesOutboxFinal.valueAt(b); - TLRPC.TL_dialog dialog = dialogs_dict.get((long) key); - if (dialog != null && dialog.top_message > 0 && dialog.top_message <= messageId) { - MessageObject obj = dialogMessage.get(dialog.id); - if (obj != null && obj.isOut()) { - obj.setIsRead(); - updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; - } - } - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + int updateMask = 0; + if (markAsReadMessagesInboxFinal != null || markAsReadMessagesOutboxFinal != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesRead, markAsReadMessagesInboxFinal, markAsReadMessagesOutboxFinal); + if (markAsReadMessagesInboxFinal != null) { + NotificationsController.getInstance(currentAccount).processReadMessages(markAsReadMessagesInboxFinal, 0, 0, 0, false); + SharedPreferences.Editor editor = notificationsPreferences.edit(); + for (int b = 0, size = markAsReadMessagesInboxFinal.size(); b < size; b++) { + int key = markAsReadMessagesInboxFinal.keyAt(b); + int messageId = (int) markAsReadMessagesInboxFinal.valueAt(b); + TLRPC.TL_dialog dialog = dialogs_dict.get((long) key); + if (dialog != null && dialog.top_message > 0 && dialog.top_message <= messageId) { + MessageObject obj = dialogMessage.get(dialog.id); + if (obj != null && !obj.isOut()) { + obj.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; } } - if (markAsReadEncryptedFinal != null) { - for (int a = 0, size = markAsReadEncryptedFinal.size(); a < size; a++) { - int key = markAsReadEncryptedFinal.keyAt(a); - int value = markAsReadEncryptedFinal.valueAt(a); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadEncrypted, key, value); - long dialog_id = (long) (key) << 32; - TLRPC.TL_dialog dialog = dialogs_dict.get(dialog_id); - if (dialog != null) { - MessageObject message = dialogMessage.get(dialog_id); - if (message != null && message.messageOwner.date <= value) { - message.setIsRead(); - updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; - } - } - } - } - if (markAsReadMessagesFinal != null) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, markAsReadMessagesFinal); - } - if (deletedMessagesFinal != null) { - for (int a = 0, size = deletedMessagesFinal.size(); a < size; a++) { - int key = deletedMessagesFinal.keyAt(a); - ArrayList arrayList = deletedMessagesFinal.valueAt(a); - if (arrayList == null) { - continue; - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, arrayList, key); - if (key == 0) { - for (int b = 0, size2 = arrayList.size(); b < size2; b++) { - Integer id = arrayList.get(b); - MessageObject obj = dialogMessagesByIds.get(id); - if (obj != null) { - obj.deleted = true; - } - } - } else { - MessageObject obj = dialogMessage.get((long) -key); - if (obj != null) { - for (int b = 0, size2 = arrayList.size(); b < size2; b++) { - if (obj.getId() == arrayList.get(b)) { - obj.deleted = true; - break; - } - } - } - } - } - NotificationsController.getInstance(currentAccount).removeDeletedMessagesFromNotifications(deletedMessagesFinal); - } - if (clearHistoryMessagesFinal != null) { - for (int a = 0, size = clearHistoryMessagesFinal.size(); a < size; a++) { - int key = clearHistoryMessagesFinal.keyAt(a); - int id = clearHistoryMessagesFinal.valueAt(a); - long did = (long) -key; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.historyCleared, did, id); - MessageObject obj = dialogMessage.get(did); - if (obj != null) { - if (obj.getId() <= id) { - obj.deleted = true; - break; - } - } - } - NotificationsController.getInstance(currentAccount).removeDeletedHisoryFromNotifications(clearHistoryMessagesFinal); - } - if (updateMask != 0) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, updateMask); + if (key != UserConfig.getInstance(currentAccount).getClientUserId()) { + editor.remove("diditem" + key); + editor.remove("diditemo" + key); } } - }); + editor.commit(); + } + if (markAsReadMessagesOutboxFinal != null) { + for (int b = 0, size = markAsReadMessagesOutboxFinal.size(); b < size; b++) { + int key = markAsReadMessagesOutboxFinal.keyAt(b); + int messageId = (int) markAsReadMessagesOutboxFinal.valueAt(b); + TLRPC.TL_dialog dialog = dialogs_dict.get((long) key); + if (dialog != null && dialog.top_message > 0 && dialog.top_message <= messageId) { + MessageObject obj = dialogMessage.get(dialog.id); + if (obj != null && obj.isOut()) { + obj.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; + } + } + } + } } - }); + if (markAsReadEncryptedFinal != null) { + for (int a = 0, size = markAsReadEncryptedFinal.size(); a < size; a++) { + int key = markAsReadEncryptedFinal.keyAt(a); + int value = markAsReadEncryptedFinal.valueAt(a); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadEncrypted, key, value); + long dialog_id = (long) (key) << 32; + TLRPC.TL_dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + MessageObject message = dialogMessage.get(dialog_id); + if (message != null && message.messageOwner.date <= value) { + message.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; + } + } + } + } + if (markAsReadMessagesFinal != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, markAsReadMessagesFinal); + } + if (deletedMessagesFinal != null) { + for (int a = 0, size = deletedMessagesFinal.size(); a < size; a++) { + int key = deletedMessagesFinal.keyAt(a); + ArrayList arrayList = deletedMessagesFinal.valueAt(a); + if (arrayList == null) { + continue; + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, arrayList, key); + if (key == 0) { + for (int b = 0, size2 = arrayList.size(); b < size2; b++) { + Integer id = arrayList.get(b); + MessageObject obj = dialogMessagesByIds.get(id); + if (obj != null) { + obj.deleted = true; + } + } + } else { + MessageObject obj = dialogMessage.get((long) -key); + if (obj != null) { + for (int b = 0, size2 = arrayList.size(); b < size2; b++) { + if (obj.getId() == arrayList.get(b)) { + obj.deleted = true; + break; + } + } + } + } + } + NotificationsController.getInstance(currentAccount).removeDeletedMessagesFromNotifications(deletedMessagesFinal); + } + if (clearHistoryMessagesFinal != null) { + for (int a = 0, size = clearHistoryMessagesFinal.size(); a < size; a++) { + int key = clearHistoryMessagesFinal.keyAt(a); + int id = clearHistoryMessagesFinal.valueAt(a); + long did = (long) -key; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.historyCleared, did, id); + MessageObject obj = dialogMessage.get(did); + if (obj != null) { + if (obj.getId() <= id) { + obj.deleted = true; + break; + } + } + } + NotificationsController.getInstance(currentAccount).removeDeletedHisoryFromNotifications(clearHistoryMessagesFinal); + } + if (updateMask != 0) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, updateMask); + } + })); if (webPages != null) { MessagesStorage.getInstance(currentAccount).putWebPages(webPages); @@ -9892,12 +9082,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (int a = 0, size = deletedMessages.size(); a < size; a++) { final int key = deletedMessages.keyAt(a); final ArrayList arrayList = deletedMessages.valueAt(a); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - ArrayList dialogIds = MessagesStorage.getInstance(currentAccount).markMessagesAsDeleted(arrayList, false, key); - MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(arrayList, dialogIds, false, key); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + ArrayList dialogIds = MessagesStorage.getInstance(currentAccount).markMessagesAsDeleted(arrayList, false, key); + MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(arrayList, dialogIds, false, key); }); } } @@ -9905,12 +9092,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (int a = 0, size = clearHistoryMessages.size(); a < size; a++) { final int key = clearHistoryMessages.keyAt(a); final int id = clearHistoryMessages.valueAt(a); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - ArrayList dialogIds = MessagesStorage.getInstance(currentAccount).markMessagesAsDeleted(key, id, false); - MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(new ArrayList(), dialogIds, false, key); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + ArrayList dialogIds = MessagesStorage.getInstance(currentAccount).markMessagesAsDeleted(key, id, false); + MessagesStorage.getInstance(currentAccount).updateDialogsWithDeletedMessages(new ArrayList<>(), dialogIds, false, key); }); } } @@ -10251,40 +9435,31 @@ public class MessagesController implements NotificationCenter.NotificationCenter request.id.add(originalMessage.getId()); req = request; } - final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - putUsers(res.users, false); - putChats(res.chats, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - fragment.presentFragment(new ChatActivity(bundle), true); - } - }); - } + final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + putUsers(res.users, false); + putChats(res.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + fragment.presentFragment(new ChatActivity(bundle), true); + }); } }); - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (fragment != null) { - fragment.setVisibleDialog(null); - } + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + if (fragment != null) { + fragment.setVisibleDialog(null); } }); fragment.setVisibleDialog(progressDialog); @@ -10358,64 +9533,50 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); req.username = username; - final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog[0].dismiss(); - } catch (Exception ignored) { + final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog[0].dismiss(); + } catch (Exception ignored) { - } - progressDialog[0] = null; - fragment.setVisibleDialog(null); - if (error == null) { - TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; - putUsers(res.users, false); - putChats(res.chats, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, false, true); - if (!res.chats.isEmpty()) { - openChatOrProfileWith(null, res.chats.get(0), fragment, 1, false); - } else if (!res.users.isEmpty()) { - openChatOrProfileWith(res.users.get(0), null, fragment, type, false); - } - } else { - if (fragment != null && fragment.getParentActivity() != null) { - try { - Toast.makeText(fragment.getParentActivity(), LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } - } - } - } - }); } - }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (progressDialog[0] == null) { - return; + progressDialog[0] = null; + fragment.setVisibleDialog(null); + if (error == null) { + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + putUsers(res.users, false); + putChats(res.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, false, true); + if (!res.chats.isEmpty()) { + openChatOrProfileWith(null, res.chats.get(0), fragment, 1, false); + } else if (!res.users.isEmpty()) { + openChatOrProfileWith(res.users.get(0), null, fragment, type, false); } - progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog[0].setCanceledOnTouchOutside(false); - progressDialog[0].setCancelable(false); - progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + } else { + if (fragment != null && fragment.getParentActivity() != null) { + try { + Toast.makeText(fragment.getParentActivity(), LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); } - }); - fragment.showDialog(progressDialog[0]); + } } + })); + AndroidUtilities.runOnUIThread(() -> { + if (progressDialog[0] == null) { + return; + } + progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog[0].setCanceledOnTouchOutside(false); + progressDialog[0].setCancelable(false); + progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + }); + fragment.showDialog(progressDialog[0]); }, 500); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index e09cb099b..7e16d2cf6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -28,7 +28,6 @@ import org.telegram.tgnet.TLRPC; import java.io.File; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -161,12 +160,7 @@ public class MessagesStorage { public MessagesStorage(int instance) { currentAccount = instance; //storageQueue.setPriority(Thread.MAX_PRIORITY); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - openDatabase(true); - } - }); + storageQueue.postRunnable(() -> openDatabase(true)); } public SQLiteDatabase getDatabase() { @@ -368,342 +362,339 @@ public class MessagesStorage { } private void updateDbToLastVersion(final int currentVersion) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int version = currentVersion; - if (version < 4) { - database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); + storageQueue.postRunnable(() -> { + try { + int version = currentVersion; + if (version < 4) { + database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); - database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose(); + database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose(); - fixNotificationSettings(); - database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); - version = 4; - } - if (version == 4) { - database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); - database.beginTransaction(); - SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1"); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); - if (cursor.next()) { - int date = cursor.intValue(0); - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - int length = data.limit(); - for (int a = 0; a < length / 4; a++) { - state.requery(); - state.bindInteger(1, data.readInt32(false)); - state.bindInteger(2, date); - state.step(); - } - data.reuse(); - } - } - state.dispose(); - cursor.dispose(); - database.commitTransaction(); - - database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose(); - database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose(); - - database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); - version = 6; - } - if (version == 6) { - database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); - version = 7; - } - /*if (version == 7 && version < 8) { - database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 8").stepThis().dispose(); - version = 8; - }*/ - if (version == 7 || version == 8 || version == 9) { - database.executeFast("ALTER TABLE enc_chats ADD COLUMN use_count INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN exchange_id INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN key_date INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN fprint INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN fauthkey BLOB default NULL").stepThis().dispose(); - database.executeFast("ALTER TABLE enc_chats ADD COLUMN khash BLOB default NULL").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 10").stepThis().dispose(); - version = 10; - } - if (version == 10) { - database.executeFast("CREATE TABLE IF NOT EXISTS web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, PRIMARY KEY (id, type));").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 11").stepThis().dispose(); - version = 11; - } - if (version == 11 || version == 12) { - database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_media;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS mid_idx_media;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS uid_date_mid_idx_media;").stepThis().dispose(); - database.executeFast("DROP TABLE IF EXISTS media;").stepThis().dispose(); - database.executeFast("DROP TABLE IF EXISTS media_counts;").stepThis().dispose(); - - database.executeFast("CREATE TABLE IF NOT EXISTS media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose(); - - database.executeFast("CREATE TABLE IF NOT EXISTS keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose(); - - database.executeFast("PRAGMA user_version = 13").stepThis().dispose(); - version = 13; - } - if (version == 13) { - database.executeFast("ALTER TABLE messages ADD COLUMN replydata BLOB default NULL").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 14").stepThis().dispose(); - version = 14; - } - if (version == 14) { - database.executeFast("CREATE TABLE IF NOT EXISTS hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 15").stepThis().dispose(); - version = 15; - } - if (version == 15) { - database.executeFast("CREATE TABLE IF NOT EXISTS webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 16").stepThis().dispose(); - version = 16; - } - if (version == 16) { - database.executeFast("ALTER TABLE dialogs ADD COLUMN inbox_max INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE dialogs ADD COLUMN outbox_max INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 17").stepThis().dispose(); - version = 17; - } - if (version == 17) { - database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 18").stepThis().dispose(); - version = 18; - } - if (version == 18) { - database.executeFast("DROP TABLE IF EXISTS stickers;").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 19").stepThis().dispose(); - version = 19; - } - if (version == 19) { - database.executeFast("CREATE TABLE IF NOT EXISTS bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 20").stepThis().dispose(); - version = 20; - } - if (version == 20) { - database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 21").stepThis().dispose(); - version = 21; - } - if (version == 21) { - database.executeFast("CREATE TABLE IF NOT EXISTS chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); - - SQLiteCursor cursor = database.queryFinalized("SELECT uid, participants FROM chat_settings WHERE uid < 0"); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)"); - while (cursor.next()) { - int chat_id = cursor.intValue(0); - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - TLRPC.ChatParticipants participants = TLRPC.ChatParticipants.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - if (participants != null) { - TLRPC.TL_chatFull chatFull = new TLRPC.TL_chatFull(); - chatFull.id = chat_id; - chatFull.chat_photo = new TLRPC.TL_photoEmpty(); - chatFull.notify_settings = new TLRPC.TL_peerNotifySettingsEmpty_layer77(); - chatFull.exported_invite = new TLRPC.TL_chatInviteEmpty(); - chatFull.participants = participants; - NativeByteBuffer data2 = new NativeByteBuffer(chatFull.getObjectSize()); - chatFull.serializeToStream(data2); - state.requery(); - state.bindInteger(1, chat_id); - state.bindByteBuffer(2, data2); - state.step(); - data2.reuse(); - } - } - } - state.dispose(); - cursor.dispose(); - - database.executeFast("DROP TABLE IF EXISTS chat_settings;").stepThis().dispose(); - database.executeFast("ALTER TABLE dialogs ADD COLUMN last_mid_i INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE dialogs ADD COLUMN unread_count_i INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE dialogs ADD COLUMN pts INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE dialogs ADD COLUMN date_i INTEGER default 0").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose(); - database.executeFast("ALTER TABLE messages ADD COLUMN imp INTEGER default 0").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 22").stepThis().dispose(); - version = 22; - } - if (version == 22) { - database.executeFast("CREATE TABLE IF NOT EXISTS media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 23").stepThis().dispose(); - version = 23; - } - if (version == 23 || version == 24) { - database.executeFast("DELETE FROM media_holes_v2 WHERE uid != 0 AND type >= 0 AND start IN (0, 1)").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 25").stepThis().dispose(); - version = 25; - } - if (version == 25 || version == 26) { - database.executeFast("CREATE TABLE IF NOT EXISTS channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 27").stepThis().dispose(); - version = 27; - } - if (version == 27) { - database.executeFast("ALTER TABLE web_recent_v3 ADD COLUMN document BLOB default NULL").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 28").stepThis().dispose(); - version = 28; - } - if (version == 28 || version == 29) { - database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); - database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 30").stepThis().dispose(); - version = 30; - } - if (version == 30) { - database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 31").stepThis().dispose(); - version = 31; - } - if (version == 31) { - database.executeFast("DROP TABLE IF EXISTS bot_recent;").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS chat_hints(did INTEGER, type INTEGER, rating REAL, date INTEGER, PRIMARY KEY(did, type))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS chat_hints_rating_idx ON chat_hints(rating);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 32").stepThis().dispose(); - version = 32; - } - if (version == 32) { - database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_imp_messages;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS uid_date_mid_imp_idx_messages;").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 33").stepThis().dispose(); - version = 33; - } - if (version == 33) { - database.executeFast("CREATE TABLE IF NOT EXISTS pending_tasks(id INTEGER PRIMARY KEY, data BLOB);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 34").stepThis().dispose(); - version = 34; - } - if (version == 34) { - database.executeFast("CREATE TABLE IF NOT EXISTS stickers_featured(id INTEGER PRIMARY KEY, data BLOB, unread BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 35").stepThis().dispose(); - version = 35; - } - if (version == 35) { - database.executeFast("CREATE TABLE IF NOT EXISTS requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 36").stepThis().dispose(); - version = 36; - } - if (version == 36) { - database.executeFast("ALTER TABLE enc_chats ADD COLUMN in_seq_no INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 37").stepThis().dispose(); - version = 37; - } - if (version == 37) { - database.executeFast("CREATE TABLE IF NOT EXISTS botcache(id TEXT PRIMARY KEY, date INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS botcache_date_idx ON botcache(date);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 38").stepThis().dispose(); - version = 38; - } - if (version == 38) { - database.executeFast("ALTER TABLE dialogs ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 39").stepThis().dispose(); - version = 39; - } - if (version == 39) { - database.executeFast("ALTER TABLE enc_chats ADD COLUMN admin_id INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 40").stepThis().dispose(); - version = 40; - } - if (version == 40) { - fixNotificationSettings(); - database.executeFast("PRAGMA user_version = 41").stepThis().dispose(); - version = 41; - } - if (version == 41) { - database.executeFast("ALTER TABLE messages ADD COLUMN mention INTEGER default 0").stepThis().dispose(); - database.executeFast("ALTER TABLE user_contacts_v6 ADD COLUMN imported INTEGER default 0").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_mention_idx_messages ON messages(uid, mention, read_state);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 42").stepThis().dispose(); - version = 42; - } - if (version == 42) { - database.executeFast("CREATE TABLE IF NOT EXISTS sharing_locations(uid INTEGER PRIMARY KEY, mid INTEGER, date INTEGER, period INTEGER, message BLOB);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 43").stepThis().dispose(); - version = 43; - } - if (version == 43) { - database.executeFast("CREATE TABLE IF NOT EXISTS channel_admins(did INTEGER, uid INTEGER, PRIMARY KEY(did, uid))").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 44").stepThis().dispose(); - version = 44; - } - if (version == 44) { - database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v7(key TEXT PRIMARY KEY, uid INTEGER, fname TEXT, sname TEXT, imported INTEGER)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v7(key TEXT, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (key, phone))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v7(sphone, deleted);").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 45").stepThis().dispose(); - version = 45; - } - if (version == 45) { - database.executeFast("ALTER TABLE enc_chats ADD COLUMN mtproto_seq INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 46").stepThis().dispose(); - version = 46; - } - if (version == 46) { - database.executeFast("DELETE FROM botcache WHERE 1").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 47").stepThis().dispose(); - version = 47; - } - if (version == 47) { - database.executeFast("ALTER TABLE dialogs ADD COLUMN flags INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 48").stepThis().dispose(); - //version = 48; - } - } catch (Exception e) { - FileLog.e(e); + fixNotificationSettings(); + database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); + version = 4; } + if (version == 4) { + database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); + database.beginTransaction(); + SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); + if (cursor.next()) { + int date = cursor.intValue(0); + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + int length = data.limit(); + for (int a = 0; a < length / 4; a++) { + state.requery(); + state.bindInteger(1, data.readInt32(false)); + state.bindInteger(2, date); + state.step(); + } + data.reuse(); + } + } + state.dispose(); + cursor.dispose(); + database.commitTransaction(); + + database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose(); + + database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + version = 6; + } + if (version == 6) { + database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); + version = 7; + } + /*if (version == 7 && version < 8) { + database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 8").stepThis().dispose(); + version = 8; + }*/ + if (version == 7 || version == 8 || version == 9) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN use_count INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN exchange_id INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN key_date INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN fprint INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN fauthkey BLOB default NULL").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN khash BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 10").stepThis().dispose(); + version = 10; + } + if (version == 10) { + database.executeFast("CREATE TABLE IF NOT EXISTS web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, PRIMARY KEY (id, type));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 11").stepThis().dispose(); + version = 11; + } + if (version == 11 || version == 12) { + database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS uid_date_mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS media;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS media_counts;").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 13").stepThis().dispose(); + version = 13; + } + if (version == 13) { + database.executeFast("ALTER TABLE messages ADD COLUMN replydata BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 14").stepThis().dispose(); + version = 14; + } + if (version == 14) { + database.executeFast("CREATE TABLE IF NOT EXISTS hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 15").stepThis().dispose(); + version = 15; + } + if (version == 15) { + database.executeFast("CREATE TABLE IF NOT EXISTS webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 16").stepThis().dispose(); + version = 16; + } + if (version == 16) { + database.executeFast("ALTER TABLE dialogs ADD COLUMN inbox_max INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN outbox_max INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 17").stepThis().dispose(); + version = 17; + } + if (version == 17) { + database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 18").stepThis().dispose(); + version = 18; + } + if (version == 18) { + database.executeFast("DROP TABLE IF EXISTS stickers;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 19").stepThis().dispose(); + version = 19; + } + if (version == 19) { + database.executeFast("CREATE TABLE IF NOT EXISTS bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 20").stepThis().dispose(); + version = 20; + } + if (version == 20) { + database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 21").stepThis().dispose(); + version = 21; + } + if (version == 21) { + database.executeFast("CREATE TABLE IF NOT EXISTS chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); + + SQLiteCursor cursor = database.queryFinalized("SELECT uid, participants FROM chat_settings WHERE uid < 0"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)"); + while (cursor.next()) { + int chat_id = cursor.intValue(0); + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.ChatParticipants participants = TLRPC.ChatParticipants.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + if (participants != null) { + TLRPC.TL_chatFull chatFull = new TLRPC.TL_chatFull(); + chatFull.id = chat_id; + chatFull.chat_photo = new TLRPC.TL_photoEmpty(); + chatFull.notify_settings = new TLRPC.TL_peerNotifySettingsEmpty_layer77(); + chatFull.exported_invite = new TLRPC.TL_chatInviteEmpty(); + chatFull.participants = participants; + NativeByteBuffer data2 = new NativeByteBuffer(chatFull.getObjectSize()); + chatFull.serializeToStream(data2); + state.requery(); + state.bindInteger(1, chat_id); + state.bindByteBuffer(2, data2); + state.step(); + data2.reuse(); + } + } + } + state.dispose(); + cursor.dispose(); + + database.executeFast("DROP TABLE IF EXISTS chat_settings;").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN last_mid_i INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN unread_count_i INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN pts INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN date_i INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose(); + database.executeFast("ALTER TABLE messages ADD COLUMN imp INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 22").stepThis().dispose(); + version = 22; + } + if (version == 22) { + database.executeFast("CREATE TABLE IF NOT EXISTS media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 23").stepThis().dispose(); + version = 23; + } + if (version == 23 || version == 24) { + database.executeFast("DELETE FROM media_holes_v2 WHERE uid != 0 AND type >= 0 AND start IN (0, 1)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 25").stepThis().dispose(); + version = 25; + } + if (version == 25 || version == 26) { + database.executeFast("CREATE TABLE IF NOT EXISTS channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 27").stepThis().dispose(); + version = 27; + } + if (version == 27) { + database.executeFast("ALTER TABLE web_recent_v3 ADD COLUMN document BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 28").stepThis().dispose(); + version = 28; + } + if (version == 28 || version == 29) { + database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); + database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 30").stepThis().dispose(); + version = 30; + } + if (version == 30) { + database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 31").stepThis().dispose(); + version = 31; + } + if (version == 31) { + database.executeFast("DROP TABLE IF EXISTS bot_recent;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS chat_hints(did INTEGER, type INTEGER, rating REAL, date INTEGER, PRIMARY KEY(did, type))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_hints_rating_idx ON chat_hints(rating);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 32").stepThis().dispose(); + version = 32; + } + if (version == 32) { + database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_imp_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS uid_date_mid_imp_idx_messages;").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 33").stepThis().dispose(); + version = 33; + } + if (version == 33) { + database.executeFast("CREATE TABLE IF NOT EXISTS pending_tasks(id INTEGER PRIMARY KEY, data BLOB);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 34").stepThis().dispose(); + version = 34; + } + if (version == 34) { + database.executeFast("CREATE TABLE IF NOT EXISTS stickers_featured(id INTEGER PRIMARY KEY, data BLOB, unread BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 35").stepThis().dispose(); + version = 35; + } + if (version == 35) { + database.executeFast("CREATE TABLE IF NOT EXISTS requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 36").stepThis().dispose(); + version = 36; + } + if (version == 36) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN in_seq_no INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 37").stepThis().dispose(); + version = 37; + } + if (version == 37) { + database.executeFast("CREATE TABLE IF NOT EXISTS botcache(id TEXT PRIMARY KEY, date INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS botcache_date_idx ON botcache(date);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 38").stepThis().dispose(); + version = 38; + } + if (version == 38) { + database.executeFast("ALTER TABLE dialogs ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 39").stepThis().dispose(); + version = 39; + } + if (version == 39) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN admin_id INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 40").stepThis().dispose(); + version = 40; + } + if (version == 40) { + fixNotificationSettings(); + database.executeFast("PRAGMA user_version = 41").stepThis().dispose(); + version = 41; + } + if (version == 41) { + database.executeFast("ALTER TABLE messages ADD COLUMN mention INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE user_contacts_v6 ADD COLUMN imported INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mention_idx_messages ON messages(uid, mention, read_state);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 42").stepThis().dispose(); + version = 42; + } + if (version == 42) { + database.executeFast("CREATE TABLE IF NOT EXISTS sharing_locations(uid INTEGER PRIMARY KEY, mid INTEGER, date INTEGER, period INTEGER, message BLOB);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 43").stepThis().dispose(); + version = 43; + } + if (version == 43) { + database.executeFast("CREATE TABLE IF NOT EXISTS channel_admins(did INTEGER, uid INTEGER, PRIMARY KEY(did, uid))").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 44").stepThis().dispose(); + version = 44; + } + if (version == 44) { + database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v7(key TEXT PRIMARY KEY, uid INTEGER, fname TEXT, sname TEXT, imported INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v7(key TEXT, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (key, phone))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v7(sphone, deleted);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 45").stepThis().dispose(); + version = 45; + } + if (version == 45) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN mtproto_seq INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 46").stepThis().dispose(); + version = 46; + } + if (version == 46) { + database.executeFast("DELETE FROM botcache WHERE 1").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 47").stepThis().dispose(); + version = 47; + } + if (version == 47) { + database.executeFast("ALTER TABLE dialogs ADD COLUMN flags INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 48").stepThis().dispose(); + //version = 48; + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -744,98 +735,84 @@ public class MessagesStorage { if (!isLogin) { storageQueue.cleanupQueue(); } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - cleanupInternal(); - openDatabase(false); - if (isLogin) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).getDifference(); - } - }); - } + storageQueue.postRunnable(() -> { + cleanupInternal(); + openDatabase(false); + if (isLogin) { + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).getDifference()); } }); } public void saveSecretParams(final int lsv, final int sg, final byte[] pbytes) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = database.executeFast("UPDATE params SET lsv = ?, sg = ?, pbytes = ? WHERE id = 1"); - state.bindInteger(1, lsv); - state.bindInteger(2, sg); - NativeByteBuffer data = new NativeByteBuffer(pbytes != null ? pbytes.length : 1); - if (pbytes != null) { - data.writeBytes(pbytes); - } - state.bindByteBuffer(3, data); - state.step(); - state.dispose(); - data.reuse(); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + SQLitePreparedStatement state = database.executeFast("UPDATE params SET lsv = ?, sg = ?, pbytes = ? WHERE id = 1"); + state.bindInteger(1, lsv); + state.bindInteger(2, sg); + NativeByteBuffer data = new NativeByteBuffer(pbytes != null ? pbytes.length : 1); + if (pbytes != null) { + data.writeBytes(pbytes); } + state.bindByteBuffer(3, data); + state.step(); + state.dispose(); + data.reuse(); + } catch (Exception e) { + FileLog.e(e); } }); } private void fixNotificationSettings() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - LongSparseArray ids = new LongSparseArray<>(); - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - Map values = preferences.getAll(); - for (Map.Entry entry : values.entrySet()) { - String key = entry.getKey(); - if (key.startsWith("notify2_")) { - Integer value = (Integer) entry.getValue(); - if (value == 2 || value == 3) { - key = key.replace("notify2_", ""); - long flags; - if (value == 2) { - flags = 1; + storageQueue.postRunnable(() -> { + try { + LongSparseArray ids = new LongSparseArray<>(); + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + Map values = preferences.getAll(); + for (Map.Entry entry : values.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("notify2_")) { + Integer value = (Integer) entry.getValue(); + if (value == 2 || value == 3) { + key = key.replace("notify2_", ""); + long flags; + if (value == 2) { + flags = 1; + } else { + Integer time = (Integer) values.get("notifyuntil_" + key); + if (time != null) { + flags = ((long) time << 32) | 1; } else { - Integer time = (Integer) values.get("notifyuntil_" + key); - if (time != null) { - flags = ((long) time << 32) | 1; - } else { - flags = 1; - } + flags = 1; } - try { - ids.put(Long.parseLong(key), flags); - } catch (Exception e) { - e.printStackTrace(); - } - } else if (value == 3) { - } + try { + ids.put(Long.parseLong(key), flags); + } catch (Exception e) { + e.printStackTrace(); + } + } else if (value == 3) { + } } - try { - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); - for (int a = 0; a < ids.size(); a++) { - state.requery(); - state.bindLong(1, ids.keyAt(a)); - state.bindLong(2, ids.valueAt(a)); - state.step(); - } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); + } + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); + for (int a = 0; a < ids.size(); a++) { + state.requery(); + state.bindLong(1, ids.keyAt(a)); + state.bindLong(2, ids.valueAt(a)); + state.step(); } - } catch (Throwable e) { + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { FileLog.e(e); } + } catch (Throwable e) { + FileLog.e(e); } }); } @@ -845,192 +822,145 @@ public class MessagesStorage { return 0; } final long id = lastTaskId.getAndAdd(1); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO pending_tasks VALUES(?, ?)"); - state.bindLong(1, id); - state.bindByteBuffer(2, data); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } finally { - data.reuse(); - } + storageQueue.postRunnable(() -> { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO pending_tasks VALUES(?, ?)"); + state.bindLong(1, id); + state.bindByteBuffer(2, data); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); + } finally { + data.reuse(); } }); return id; } public void removePendingTask(final long id) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM pending_tasks WHERE id = " + id).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM pending_tasks WHERE id = " + id).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } private void loadPendingTasks() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT id, data FROM pending_tasks WHERE 1"); - while (cursor.next()) { - final long taskId = cursor.longValue(0); - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - int type = data.readInt32(false); - switch (type) { - case 0: { - final TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); - if (chat != null) { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).loadUnknownChannel(chat, taskId); - } - }); - } - break; - } - case 1: { - final int channelId = data.readInt32(false); - final int newDialogType = data.readInt32(false); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).getChannelDifference(channelId, newDialogType, taskId, null); - } - }); - break; - } - case 2: - case 5: - case 8: - case 10: { - final TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); - dialog.id = data.readInt64(false); - dialog.top_message = data.readInt32(false); - dialog.read_inbox_max_id = data.readInt32(false); - dialog.read_outbox_max_id = data.readInt32(false); - dialog.unread_count = data.readInt32(false); - dialog.last_message_date = data.readInt32(false); - dialog.pts = data.readInt32(false); - dialog.flags = data.readInt32(false); - if (type >= 5) { - dialog.pinned = data.readBool(false); - dialog.pinnedNum = data.readInt32(false); - } - if (type >= 8) { - dialog.unread_mentions_count = data.readInt32(false); - } - if (type >= 10) { - dialog.unread_mark = data.readBool(false); - } - final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).checkLastDialogMessage(dialog, peer, taskId); - } - }); - break; - } - case 3: { - long random_id = data.readInt64(false); - TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); - TLRPC.TL_inputMediaGame game = (TLRPC.TL_inputMediaGame) TLRPC.InputMedia.TLdeserialize(data, data.readInt32(false), false); - SendMessagesHelper.getInstance(currentAccount).sendGame(peer, game, random_id, taskId); - break; - } - case 4: { - final long did = data.readInt64(false); - final boolean pin = data.readBool(false); - final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).pinDialog(did, pin, peer, taskId); - } - }); - break; - } - case 6: { - final int channelId = data.readInt32(false); - final int newDialogType = data.readInt32(false); - final TLRPC.InputChannel inputChannel = TLRPC.InputChannel.TLdeserialize(data, data.readInt32(false), false); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).getChannelDifference(channelId, newDialogType, taskId, inputChannel); - } - }); - break; - } - case 7: { - final int channelId = data.readInt32(false); - int constructor = data.readInt32(false); - TLObject request = TLRPC.TL_messages_deleteMessages.TLdeserialize(data, constructor, false); - if (request == null) { - request = TLRPC.TL_channels_deleteMessages.TLdeserialize(data, constructor, false); - } - if (request == null) { - removePendingTask(taskId); - } else { - final TLObject finalRequest = request; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).deleteMessages(null, null, null, channelId, true, taskId, finalRequest); - } - }); - } - break; - } - case 9: { - final long did = data.readInt64(false); - final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).markDialogAsUnread(did, peer, taskId); - } - }); - break; + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT id, data FROM pending_tasks WHERE 1"); + while (cursor.next()) { + final long taskId = cursor.longValue(0); + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + int type = data.readInt32(false); + switch (type) { + case 0: { + final TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); + if (chat != null) { + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).loadUnknownChannel(chat, taskId)); } + break; + } + case 1: { + final int channelId = data.readInt32(false); + final int newDialogType = data.readInt32(false); + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).getChannelDifference(channelId, newDialogType, taskId, null)); + break; + } + case 2: + case 5: + case 8: + case 10: { + final TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); + dialog.id = data.readInt64(false); + dialog.top_message = data.readInt32(false); + dialog.read_inbox_max_id = data.readInt32(false); + dialog.read_outbox_max_id = data.readInt32(false); + dialog.unread_count = data.readInt32(false); + dialog.last_message_date = data.readInt32(false); + dialog.pts = data.readInt32(false); + dialog.flags = data.readInt32(false); + if (type >= 5) { + dialog.pinned = data.readBool(false); + dialog.pinnedNum = data.readInt32(false); + } + if (type >= 8) { + dialog.unread_mentions_count = data.readInt32(false); + } + if (type >= 10) { + dialog.unread_mark = data.readBool(false); + } + final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).checkLastDialogMessage(dialog, peer, taskId)); + break; + } + case 3: { + long random_id = data.readInt64(false); + TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); + TLRPC.TL_inputMediaGame game = (TLRPC.TL_inputMediaGame) TLRPC.InputMedia.TLdeserialize(data, data.readInt32(false), false); + SendMessagesHelper.getInstance(currentAccount).sendGame(peer, game, random_id, taskId); + break; + } + case 4: { + final long did = data.readInt64(false); + final boolean pin = data.readBool(false); + final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).pinDialog(did, pin, peer, taskId)); + break; + } + case 6: { + final int channelId = data.readInt32(false); + final int newDialogType = data.readInt32(false); + final TLRPC.InputChannel inputChannel = TLRPC.InputChannel.TLdeserialize(data, data.readInt32(false), false); + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).getChannelDifference(channelId, newDialogType, taskId, inputChannel)); + break; + } + case 7: { + final int channelId = data.readInt32(false); + int constructor = data.readInt32(false); + TLObject request = TLRPC.TL_messages_deleteMessages.TLdeserialize(data, constructor, false); + if (request == null) { + request = TLRPC.TL_channels_deleteMessages.TLdeserialize(data, constructor, false); + } + if (request == null) { + removePendingTask(taskId); + } else { + final TLObject finalRequest = request; + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).deleteMessages(null, null, null, channelId, true, taskId, finalRequest)); + } + break; + } + case 9: { + final long did = data.readInt64(false); + final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).markDialogAsUnread(did, peer, taskId)); + break; } - data.reuse(); } + data.reuse(); } - cursor.dispose(); - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void saveChannelPts(final int channelId, final int pts) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pts = ? WHERE did = ?"); - state.bindInteger(1, pts); - state.bindInteger(2, -channelId); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pts = ? WHERE did = ?"); + state.bindInteger(1, pts); + state.bindInteger(2, -channelId); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -1057,293 +987,266 @@ public class MessagesStorage { } public void saveDiffParams(final int seq, final int pts, final int date, final int qts) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - saveDiffParamsInternal(seq, pts, date, qts); - } - }); + storageQueue.postRunnable(() -> saveDiffParamsInternal(seq, pts, date, qts)); } public void setDialogFlags(final long did, final long flags) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast(String.format(Locale.US, "REPLACE INTO dialog_settings VALUES(%d, %d)", did, flags)).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast(String.format(Locale.US, "REPLACE INTO dialog_settings VALUES(%d, %d)", did, flags)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void loadUnreadMessages() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList encryptedChatIds = new ArrayList<>(); + storageQueue.postRunnable(() -> { + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedChatIds = new ArrayList<>(); - final LongSparseArray pushDialogs = new LongSparseArray<>(); - SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0"); - StringBuilder ids = new StringBuilder(); - int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - while (cursor.next()) { - long flags = cursor.longValue(2); - boolean muted = (flags & 1) != 0; - int mutedUntil = (int) (flags >> 32); - if (cursor.isNull(2) || !muted || mutedUntil != 0 && mutedUntil < currentTime) { - long did = cursor.longValue(0); - int count = cursor.intValue(1); - pushDialogs.put(did, count); - if (ids.length() != 0) { - ids.append(","); - } - ids.append(did); - int lower_id = (int) did; - int high_id = (int) (did >> 32); - if (lower_id != 0) { - if (lower_id < 0) { - if (!chatsToLoad.contains(-lower_id)) { - chatsToLoad.add(-lower_id); - } - } else { - if (!usersToLoad.contains(lower_id)) { - usersToLoad.add(lower_id); - } + final LongSparseArray pushDialogs = new LongSparseArray<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0"); + StringBuilder ids = new StringBuilder(); + int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + while (cursor.next()) { + long flags = cursor.longValue(2); + boolean muted = (flags & 1) != 0; + int mutedUntil = (int) (flags >> 32); + if (cursor.isNull(2) || !muted || mutedUntil != 0 && mutedUntil < currentTime) { + long did = cursor.longValue(0); + int count = cursor.intValue(1); + pushDialogs.put(did, count); + if (ids.length() != 0) { + ids.append(","); + } + ids.append(did); + int lower_id = (int) did; + int high_id = (int) (did >> 32); + if (lower_id != 0) { + if (lower_id < 0) { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); } } else { - if (!encryptedChatIds.contains(high_id)) { - encryptedChatIds.add(high_id); + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); } } + } else { + if (!encryptedChatIds.contains(high_id)) { + encryptedChatIds.add(high_id); + } + } + } + } + cursor.dispose(); + + ArrayList replyMessages = new ArrayList<>(); + SparseArray> replyMessageOwners = new SparseArray<>(); + final ArrayList messages = new ArrayList<>(); + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + final ArrayList encryptedChats = new ArrayList<>(); + if (ids.length() > 0) { + cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid, replydata FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state IN(0,2) ORDER BY date DESC LIMIT 50"); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + message.date = cursor.intValue(4); + message.dialog_id = cursor.longValue(5); + messages.add(message); + + int lower_id = (int) message.dialog_id; + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + message.send_state = cursor.intValue(2); + if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { + message.send_state = 0; + } + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + + try { + if (message.reply_to_msg_id != 0 && ( + message.action instanceof TLRPC.TL_messageActionPinMessage || + message.action instanceof TLRPC.TL_messageActionPaymentSent || + message.action instanceof TLRPC.TL_messageActionGameScore)) { + if (!cursor.isNull(6)) { + data = cursor.byteBufferValue(6); + if (data != null) { + message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message.replyMessage != null) { + if (MessageObject.isMegagroup(message)) { + message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); + } + } + } + if (message.replyMessage == null) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + ArrayList arrayList = replyMessageOwners.get(message.reply_to_msg_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + replyMessageOwners.put(message.reply_to_msg_id, arrayList); + } + arrayList.add(message); + } + } + } catch (Exception e) { + FileLog.e(e); + } } } cursor.dispose(); - ArrayList replyMessages = new ArrayList<>(); - SparseArray> replyMessageOwners = new SparseArray<>(); - final ArrayList messages = new ArrayList<>(); - final ArrayList users = new ArrayList<>(); - final ArrayList chats = new ArrayList<>(); - final ArrayList encryptedChats = new ArrayList<>(); - if (ids.length() > 0) { - cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid, replydata FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state IN(0,2) ORDER BY date DESC LIMIT 50"); + if (!replyMessages.isEmpty()) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(1); + NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); data.reuse(); - MessageObject.setUnreadFlags(message, cursor.intValue(0)); - message.id = cursor.intValue(3); - message.date = cursor.intValue(4); - message.dialog_id = cursor.longValue(5); - messages.add(message); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = cursor.longValue(3); - int lower_id = (int) message.dialog_id; addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - message.send_state = cursor.intValue(2); - if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { - message.send_state = 0; - } - if (lower_id == 0 && !cursor.isNull(5)) { - message.random_id = cursor.longValue(5); - } - try { - if (message.reply_to_msg_id != 0 && ( - message.action instanceof TLRPC.TL_messageActionPinMessage || - message.action instanceof TLRPC.TL_messageActionPaymentSent || - message.action instanceof TLRPC.TL_messageActionGameScore)) { - if (!cursor.isNull(6)) { - data = cursor.byteBufferValue(6); - if (data != null) { - message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message.replyMessage != null) { - if (MessageObject.isMegagroup(message)) { - message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); - } - } - } - if (message.replyMessage == null) { - long messageId = message.reply_to_msg_id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; - } - if (!replyMessages.contains(messageId)) { - replyMessages.add(messageId); - } - ArrayList arrayList = replyMessageOwners.get(message.reply_to_msg_id); - if (arrayList == null) { - arrayList = new ArrayList<>(); - replyMessageOwners.put(message.reply_to_msg_id, arrayList); - } - arrayList.add(message); + ArrayList arrayList = replyMessageOwners.get(message.id); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message m = arrayList.get(a); + m.replyMessage = message; + if (MessageObject.isMegagroup(m)) { + m.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } } - } catch (Exception e) { - FileLog.e(e); } } } cursor.dispose(); + } - if (!replyMessages.isEmpty()) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.dialog_id = cursor.longValue(3); + if (!encryptedChatIds.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); + } - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), users); + } - ArrayList arrayList = replyMessageOwners.get(message.id); - if (arrayList != null) { - for (int a = 0; a < arrayList.size(); a++) { - TLRPC.Message m = arrayList.get(a); - m.replyMessage = message; - if (MessageObject.isMegagroup(m)) { - m.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } - } - } - } - cursor.dispose(); - } - - if (!encryptedChatIds.isEmpty()) { - getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); - } - - if (!usersToLoad.isEmpty()) { - getUsersInternal(TextUtils.join(",", usersToLoad), users); - } - - if (!chatsToLoad.isEmpty()) { - getChatsInternal(TextUtils.join(",", chatsToLoad), chats); - for (int a = 0; a < chats.size(); a++) { - TLRPC.Chat chat = chats.get(a); - if (chat != null && (chat.left || chat.migrated_to != null)) { - long did = -chat.id; - database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose(); - database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 3 WHERE uid = %d AND mid > 0 AND read_state IN(0,2) AND out = 0", did)).stepThis().dispose(); - chats.remove(a); - a--; - pushDialogs.remove((long) -chat.id); - for (int b = 0; b < messages.size(); b++) { - TLRPC.Message message = messages.get(b); - if (message.dialog_id == -chat.id) { - messages.remove(b); - b--; - } + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + if (chat != null && (chat.left || chat.migrated_to != null)) { + long did = -chat.id; + database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 3 WHERE uid = %d AND mid > 0 AND read_state IN(0,2) AND out = 0", did)).stepThis().dispose(); + chats.remove(a); + a--; + pushDialogs.remove((long) -chat.id); + for (int b = 0; b < messages.size(); b++) { + TLRPC.Message message = messages.get(b); + if (message.dialog_id == -chat.id) { + messages.remove(b); + b--; } } } } } - Collections.reverse(messages); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats); - } - }); - } catch (Exception e) { - FileLog.e(e); } + Collections.reverse(messages); + AndroidUtilities.runOnUIThread(() -> NotificationsController.getInstance(currentAccount).processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats)); + } catch (Exception e) { + FileLog.e(e); } }); } public void putWallpapers(final ArrayList wallPapers) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int num = 0; - database.executeFast("DELETE FROM wallpapers WHERE 1").stepThis().dispose(); - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO wallpapers VALUES(?, ?)"); - for (TLRPC.WallPaper wallPaper : wallPapers) { - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(wallPaper.getObjectSize()); - wallPaper.serializeToStream(data); - state.bindInteger(1, num); - state.bindByteBuffer(2, data); - state.step(); - num++; - data.reuse(); - } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + int num = 0; + database.executeFast("DELETE FROM wallpapers WHERE 1").stepThis().dispose(); + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO wallpapers VALUES(?, ?)"); + for (TLRPC.WallPaper wallPaper : wallPapers) { + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(wallPaper.getObjectSize()); + wallPaper.serializeToStream(data); + state.bindInteger(1, num); + state.bindByteBuffer(2, data); + state.step(); + num++; + data.reuse(); } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); } }); } public void loadWebRecent(final int type) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT id, image_url, thumb_url, local_url, width, height, size, date, document FROM web_recent_v3 WHERE type = " + type + " ORDER BY date DESC"); - final ArrayList arrayList = new ArrayList<>(); - while (cursor.next()) { - MediaController.SearchImage searchImage = new MediaController.SearchImage(); - searchImage.id = cursor.stringValue(0); - searchImage.imageUrl = cursor.stringValue(1); - searchImage.thumbUrl = cursor.stringValue(2); - searchImage.localUrl = cursor.stringValue(3); - searchImage.width = cursor.intValue(4); - searchImage.height = cursor.intValue(5); - searchImage.size = cursor.intValue(6); - searchImage.date = cursor.intValue(7); - if (!cursor.isNull(8)) { - NativeByteBuffer data = cursor.byteBufferValue(8); - if (data != null) { - int constructor = data.readInt32(false); - searchImage.document = TLRPC.Document.TLdeserialize(data, constructor, false); - if (searchImage.document == null) { - searchImage.photo = TLRPC.Photo.TLdeserialize(data, constructor, false); - if (searchImage.photo != null) { - TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(searchImage.photo.sizes, AndroidUtilities.getPhotoSize()); - TLRPC.PhotoSize size2 = FileLoader.getClosestPhotoSizeWithSize(searchImage.photo.sizes, 80); - searchImage.photoSize = size; - searchImage.thumbPhotoSize = size2; - } + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT id, image_url, thumb_url, local_url, width, height, size, date, document FROM web_recent_v3 WHERE type = " + type + " ORDER BY date DESC"); + final ArrayList arrayList = new ArrayList<>(); + while (cursor.next()) { + MediaController.SearchImage searchImage = new MediaController.SearchImage(); + searchImage.id = cursor.stringValue(0); + searchImage.imageUrl = cursor.stringValue(1); + searchImage.thumbUrl = cursor.stringValue(2); + searchImage.localUrl = cursor.stringValue(3); + searchImage.width = cursor.intValue(4); + searchImage.height = cursor.intValue(5); + searchImage.size = cursor.intValue(6); + searchImage.date = cursor.intValue(7); + if (!cursor.isNull(8)) { + NativeByteBuffer data = cursor.byteBufferValue(8); + if (data != null) { + int constructor = data.readInt32(false); + searchImage.document = TLRPC.Document.TLdeserialize(data, constructor, false); + if (searchImage.document == null) { + searchImage.photo = TLRPC.Photo.TLdeserialize(data, constructor, false); + if (searchImage.photo != null) { + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(searchImage.photo.sizes, AndroidUtilities.getPhotoSize()); + TLRPC.PhotoSize size2 = FileLoader.getClosestPhotoSizeWithSize(searchImage.photo.sizes, 80); + searchImage.photoSize = size; + searchImage.thumbPhotoSize = size2; } - data.reuse(); } + data.reuse(); } - searchImage.type = type; - arrayList.add(searchImage); } - cursor.dispose(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recentImagesDidLoaded, type, arrayList); - } - }); - } catch (Throwable e) { - FileLog.e(e); + searchImage.type = type; + arrayList.add(searchImage); } + cursor.dispose(); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recentImagesDidLoaded, type, arrayList)); + } catch (Throwable e) { + FileLog.e(e); } }); } @@ -1352,210 +1255,245 @@ public class MessagesStorage { if (imageUrl == null || imageUrl.length() == 0 || ((localUrl == null || localUrl.length() == 0) && document == null)) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (document != null) { - SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET document = ? WHERE image_url = ?"); - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(document.getObjectSize()); - document.serializeToStream(data); - state.bindByteBuffer(1, data); - state.bindString(2, imageUrl); - state.step(); - state.dispose(); - data.reuse(); - } else { - SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET local_url = ? WHERE image_url = ?"); - state.requery(); - state.bindString(1, localUrl); - state.bindString(2, imageUrl); - state.step(); - state.dispose(); - } - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (document != null) { + SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET document = ? WHERE image_url = ?"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(document.getObjectSize()); + document.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindString(2, imageUrl); + state.step(); + state.dispose(); + data.reuse(); + } else { + SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET local_url = ? WHERE image_url = ?"); + state.requery(); + state.bindString(1, localUrl); + state.bindString(2, imageUrl); + state.step(); + state.dispose(); } + } catch (Exception e) { + FileLog.e(e); } }); } public void clearWebRecent(final int type) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM web_recent_v3 WHERE type = " + type).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM web_recent_v3 WHERE type = " + type).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void putWebRecent(final ArrayList arrayList) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO web_recent_v3 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - for (int a = 0; a < arrayList.size(); a++) { - if (a == 200) { - break; - } - MediaController.SearchImage searchImage = arrayList.get(a); - state.requery(); - state.bindString(1, searchImage.id); - state.bindInteger(2, searchImage.type); - state.bindString(3, searchImage.imageUrl != null ? searchImage.imageUrl : ""); - state.bindString(4, searchImage.thumbUrl != null ? searchImage.thumbUrl : ""); - state.bindString(5, searchImage.localUrl != null ? searchImage.localUrl : ""); - state.bindInteger(6, searchImage.width); - state.bindInteger(7, searchImage.height); - state.bindInteger(8, searchImage.size); - state.bindInteger(9, searchImage.date); - NativeByteBuffer data = null; - if (searchImage.photo != null) { - data = new NativeByteBuffer(searchImage.photo.getObjectSize()); - searchImage.photo.serializeToStream(data); - state.bindByteBuffer(10, data); - } else if (searchImage.document != null) { - data = new NativeByteBuffer(searchImage.document.getObjectSize()); - searchImage.document.serializeToStream(data); - state.bindByteBuffer(10, data); - } else { - state.bindNull(10); - } - state.step(); - if (data != null) { - data.reuse(); - } + storageQueue.postRunnable(() -> { + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO web_recent_v3 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + for (int a = 0; a < arrayList.size(); a++) { + if (a == 200) { + break; } - state.dispose(); - database.commitTransaction(); - if (arrayList.size() >= 200) { - database.beginTransaction(); - for (int a = 200; a < arrayList.size(); a++) { - database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + arrayList.get(a).id + "'").stepThis().dispose(); - } - database.commitTransaction(); + MediaController.SearchImage searchImage = arrayList.get(a); + state.requery(); + state.bindString(1, searchImage.id); + state.bindInteger(2, searchImage.type); + state.bindString(3, searchImage.imageUrl != null ? searchImage.imageUrl : ""); + state.bindString(4, searchImage.thumbUrl != null ? searchImage.thumbUrl : ""); + state.bindString(5, searchImage.localUrl != null ? searchImage.localUrl : ""); + state.bindInteger(6, searchImage.width); + state.bindInteger(7, searchImage.height); + state.bindInteger(8, searchImage.size); + state.bindInteger(9, searchImage.date); + NativeByteBuffer data = null; + if (searchImage.photo != null) { + data = new NativeByteBuffer(searchImage.photo.getObjectSize()); + searchImage.photo.serializeToStream(data); + state.bindByteBuffer(10, data); + } else if (searchImage.document != null) { + data = new NativeByteBuffer(searchImage.document.getObjectSize()); + searchImage.document.serializeToStream(data); + state.bindByteBuffer(10, data); + } else { + state.bindNull(10); + } + state.step(); + if (data != null) { + data.reuse(); } - } catch (Exception e) { - FileLog.e(e); } + state.dispose(); + database.commitTransaction(); + if (arrayList.size() >= 200) { + database.beginTransaction(); + for (int a = 200; a < arrayList.size(); a++) { + database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + arrayList.get(a).id + "'").stepThis().dispose(); + } + database.commitTransaction(); + } + } catch (Exception e) { + FileLog.e(e); } }); } public void getWallpapers() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT data FROM wallpapers WHERE 1"); - final ArrayList wallPapers = new ArrayList<>(); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.WallPaper wallPaper = TLRPC.WallPaper.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - wallPapers.add(wallPaper); - } + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT data FROM wallpapers WHERE 1"); + final ArrayList wallPapers = new ArrayList<>(); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.WallPaper wallPaper = TLRPC.WallPaper.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + wallPapers.add(wallPaper); } - cursor.dispose(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.wallpapersDidLoaded, wallPapers); - } - }); - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.wallpapersDidLoaded, wallPapers)); + } catch (Exception e) { + FileLog.e(e); } }); } public void getBlockedUsers() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - ArrayList ids = new ArrayList<>(); - ArrayList users = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized("SELECT * FROM blocked_users WHERE 1"); - StringBuilder usersToLoad = new StringBuilder(); - while (cursor.next()) { - int user_id = cursor.intValue(0); - ids.add(user_id); - if (usersToLoad.length() != 0) { - usersToLoad.append(","); - } - usersToLoad.append(user_id); - } - cursor.dispose(); - + storageQueue.postRunnable(() -> { + try { + SparseIntArray ids = new SparseIntArray(); + ArrayList users = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT * FROM blocked_users WHERE 1"); + StringBuilder usersToLoad = new StringBuilder(); + while (cursor.next()) { + int user_id = cursor.intValue(0); + ids.put(user_id, 1); if (usersToLoad.length() != 0) { - getUsersInternal(usersToLoad.toString(), users); + usersToLoad.append(","); } - - MessagesController.getInstance(currentAccount).processLoadedBlockedUsers(ids, users, true); - } catch (Exception e) { - FileLog.e(e); + usersToLoad.append(user_id); } + cursor.dispose(); + + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), users); + } + + MessagesController.getInstance(currentAccount).processLoadedBlockedUsers(ids, users, true); + } catch (Exception e) { + FileLog.e(e); } }); } public void deleteBlockedUser(final int id) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM blocked_users WHERE uid = " + id).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM blocked_users WHERE uid = " + id).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } - public void putBlockedUsers(final ArrayList ids, final boolean replace) { - if (ids == null || ids.isEmpty()) { + public void putBlockedUsers(final SparseIntArray ids, final boolean replace) { + if (ids == null || ids.size() == 0) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (replace) { - database.executeFast("DELETE FROM blocked_users WHERE 1").stepThis().dispose(); - } - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO blocked_users VALUES(?)"); - for (Integer id : ids) { - state.requery(); - state.bindInteger(1, id); - state.step(); - } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (replace) { + database.executeFast("DELETE FROM blocked_users WHERE 1").stepThis().dispose(); } + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO blocked_users VALUES(?)"); + for (int a = 0, size = ids.size(); a < size; a++) { + state.requery(); + state.bindInteger(1, ids.keyAt(a)); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); } }); } public void deleteUserChannelHistory(final int channelId, final int uid) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { + storageQueue.postRunnable(() -> { + try { + long did = -channelId; + final ArrayList mids = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); + ArrayList filesToDelete = new ArrayList<>(); try { - long did = -channelId; - final ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message != null && message.from_id == uid && message.id != 1) { + mids.add(message.id); + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + File file = FileLoader.getPathToAttach(message.media.document); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.document.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } + } + } + } catch (Exception e) { + FileLog.e(e); + } + cursor.dispose(); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).markChannelDialogMessageAsDeleted(mids, channelId)); + markMessagesAsDeletedInternal(mids, channelId); + updateDialogsWithDeletedMessagesInternal(mids, null, channelId); + FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, 0); + if (!mids.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, mids, channelId)); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void deleteDialog(final long did, final int messagesOnly) { + storageQueue.postRunnable(() -> { + try { + if (messagesOnly == 3) { + int lastMid = -1; + SQLiteCursor cursor = database.queryFinalized("SELECT last_mid FROM dialogs WHERE did = " + did); + if (cursor.next()) { + lastMid = cursor.intValue(0); + } + cursor.dispose(); + if (lastMid != 0) { + return; + } + } + if ((int) did == 0 || messagesOnly == 2) { SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); ArrayList filesToDelete = new ArrayList<>(); try { @@ -1565,8 +1503,7 @@ public class MessagesStorage { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); data.reuse(); - if (message != null && message.from_id == uid && message.id != 1) { - mids.add(message.id); + if (message != null && message.media != null) { if (message.media instanceof TLRPC.TL_messageMediaPhoto) { for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { File file = FileLoader.getPathToAttach(photoSize); @@ -1591,365 +1528,264 @@ public class MessagesStorage { FileLog.e(e); } cursor.dispose(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).markChannelDialogMessageAsDeleted(mids, channelId); - } - }); - markMessagesAsDeletedInternal(mids, channelId); - updateDialogsWithDeletedMessagesInternal(mids, null, channelId); - FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, 0); - if (!mids.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, mids, channelId); - } - }); - } - } catch (Exception e) { - FileLog.e(e); + FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, messagesOnly); } - } - }); - } - public void deleteDialog(final long did, final int messagesOnly) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (messagesOnly == 3) { - int lastMid = -1; - SQLiteCursor cursor = database.queryFinalized("SELECT last_mid FROM dialogs WHERE did = " + did); - if (cursor.next()) { - lastMid = cursor.intValue(0); - } - cursor.dispose(); - if (lastMid != 0) { - return; + if (messagesOnly == 0 || messagesOnly == 3) { + database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose(); + int lower_id = (int) did; + int high_id = (int) (did >> 32); + if (lower_id != 0) { + if (high_id == 1) { + database.executeFast("DELETE FROM chats WHERE uid = " + lower_id).stepThis().dispose(); + } else if (lower_id < 0) { + //database.executeFast("DELETE FROM chats WHERE uid = " + (-lower_id)).stepThis().dispose(); } + } else { + database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose(); + //database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose(); } - if ((int) did == 0 || messagesOnly == 2) { - SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); - ArrayList filesToDelete = new ArrayList<>(); + } else if (messagesOnly == 2) { + SQLiteCursor cursor = database.queryFinalized("SELECT last_mid_i, last_mid FROM dialogs WHERE did = " + did); + int messageId = -1; + if (cursor.next()) { + long last_mid_i = cursor.longValue(0); + long last_mid = cursor.longValue(1); + SQLiteCursor cursor2 = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did + " AND mid IN (" + last_mid_i + "," + last_mid + ")"); try { - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); + while (cursor2.next()) { + NativeByteBuffer data = cursor2.byteBufferValue(0); if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); data.reuse(); - if (message != null && message.media != null) { - if (message.media instanceof TLRPC.TL_messageMediaPhoto) { - for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { - File file = FileLoader.getPathToAttach(photoSize); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - } - } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { - File file = FileLoader.getPathToAttach(message.media.document); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - file = FileLoader.getPathToAttach(message.media.document.thumb); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - } + if (message != null) { + messageId = message.id; } } } } catch (Exception e) { FileLog.e(e); } - cursor.dispose(); - FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, messagesOnly); + cursor2.dispose(); + + database.executeFast("DELETE FROM messages WHERE uid = " + did + " AND mid != " + last_mid_i + " AND mid != " + last_mid).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); + + SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + if (messageId != -1) { + createFirstHoles(did, state5, state6, messageId); + } + state5.dispose(); + state6.dispose(); } - - if (messagesOnly == 0 || messagesOnly == 3) { - database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose(); - int lower_id = (int) did; - int high_id = (int) (did >> 32); - if (lower_id != 0) { - if (high_id == 1) { - database.executeFast("DELETE FROM chats WHERE uid = " + lower_id).stepThis().dispose(); - } else if (lower_id < 0) { - //database.executeFast("DELETE FROM chats WHERE uid = " + (-lower_id)).stepThis().dispose(); - } - } else { - database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose(); - //database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose(); - } - } else if (messagesOnly == 2) { - SQLiteCursor cursor = database.queryFinalized("SELECT last_mid_i, last_mid FROM dialogs WHERE did = " + did); - int messageId = -1; - if (cursor.next()) { - long last_mid_i = cursor.longValue(0); - long last_mid = cursor.longValue(1); - SQLiteCursor cursor2 = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did + " AND mid IN (" + last_mid_i + "," + last_mid + ")"); - try { - while (cursor2.next()) { - NativeByteBuffer data = cursor2.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message != null) { - messageId = message.id; - } - } - } - } catch (Exception e) { - FileLog.e(e); - } - cursor2.dispose(); - - database.executeFast("DELETE FROM messages WHERE uid = " + did + " AND mid != " + last_mid_i + " AND mid != " + last_mid).stepThis().dispose(); - database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); - DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); - - SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); - SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); - if (messageId != -1) { - createFirstHoles(did, state5, state6, messageId); - } - state5.dispose(); - state6.dispose(); - } - cursor.dispose(); - return; - } - - database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); - DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); - } - }); - } catch (Exception e) { - FileLog.e(e); + cursor.dispose(); + return; } + + database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needReloadRecentDialogsSearch)); + } catch (Exception e) { + FileLog.e(e); } }); } public void getDialogPhotos(final int did, final int count, final long max_id, final int classGuid) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor; + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor; - if (max_id != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d AND id < %d ORDER BY id DESC LIMIT %d", did, max_id, count)); - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY id DESC LIMIT %d", did, count)); - } - - final TLRPC.photos_Photos res = new TLRPC.TL_photos_photos(); - - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - res.photos.add(photo); - } - } - cursor.dispose(); - - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processLoadedUserPhotos(res, did, count, max_id, true, classGuid); - } - }); - } catch (Exception e) { - FileLog.e(e); + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d AND id < %d ORDER BY id DESC LIMIT %d", did, max_id, count)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY id DESC LIMIT %d", did, count)); } + + final TLRPC.photos_Photos res = new TLRPC.TL_photos_photos(); + + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + res.photos.add(photo); + } + } + cursor.dispose(); + + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processLoadedUserPhotos(res, did, count, max_id, true, classGuid)); + } catch (Exception e) { + FileLog.e(e); } }); } public void clearUserPhotos(final int uid) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM user_photos WHERE uid = " + uid).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + uid).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void clearUserPhoto(final int uid, final long pid) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM user_photos WHERE uid = " + uid + " AND id = " + pid).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + uid + " AND id = " + pid).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void resetDialogs(final TLRPC.messages_Dialogs dialogsRes, final int messagesCount, final int seq, final int newPts, final int date, final int qts, final LongSparseArray new_dialogs_dict, final LongSparseArray new_dialogMessage, final TLRPC.Message lastMessage, final int dialogsCount) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int maxPinnedNum = 0; + storageQueue.postRunnable(() -> { + try { + int maxPinnedNum = 0; - ArrayList dids = new ArrayList<>(); + ArrayList dids = new ArrayList<>(); - int totalPinnedCount = dialogsRes.dialogs.size() - dialogsCount; - final LongSparseArray oldPinnedDialogNums = new LongSparseArray<>(); - ArrayList oldPinnedOrder = new ArrayList<>(); - ArrayList orderArrayList = new ArrayList<>(); + int totalPinnedCount = dialogsRes.dialogs.size() - dialogsCount; + final LongSparseArray oldPinnedDialogNums = new LongSparseArray<>(); + ArrayList oldPinnedOrder = new ArrayList<>(); + ArrayList orderArrayList = new ArrayList<>(); - for (int a = dialogsCount; a < dialogsRes.dialogs.size(); a++) { - TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(a); - orderArrayList.add(dialog.id); - } - - SQLiteCursor cursor = database.queryFinalized("SELECT did, pinned FROM dialogs WHERE 1"); - while (cursor.next()) { - long did = cursor.longValue(0); - int pinnedNum = cursor.intValue(1); - int lower_id = (int) did; - if (lower_id != 0) { - dids.add(lower_id); - if (pinnedNum > 0) { - maxPinnedNum = Math.max(pinnedNum, maxPinnedNum); - oldPinnedDialogNums.put(did, pinnedNum); - oldPinnedOrder.add(did); - } - } - } - Collections.sort(oldPinnedOrder, new Comparator() { - @Override - public int compare(Long o1, Long o2) { - Integer val1 = oldPinnedDialogNums.get(o1); - Integer val2 = oldPinnedDialogNums.get(o2); - if (val1 < val2) { - return 1; - } else if (val1 > val2) { - return -1; - } - return 0; - } - }); - while (oldPinnedOrder.size() < totalPinnedCount) { - oldPinnedOrder.add(0, 0L); - } - cursor.dispose(); - String ids = "(" + TextUtils.join(",", dids) + ")"; - - database.beginTransaction(); - database.executeFast("DELETE FROM dialogs WHERE did IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM messages WHERE uid IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM bot_keyboard WHERE uid IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM media_counts_v2 WHERE uid IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM media_v2 WHERE uid IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM messages_holes WHERE uid IN " + ids).stepThis().dispose(); - database.executeFast("DELETE FROM media_holes_v2 WHERE uid IN " + ids).stepThis().dispose(); - database.commitTransaction(); - - for (int a = 0; a < totalPinnedCount; a++) { - TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(dialogsCount + a); - int oldIdx = oldPinnedOrder.indexOf(dialog.id); - int newIdx = orderArrayList.indexOf(dialog.id); - if (oldIdx != -1 && newIdx != -1) { - if (oldIdx == newIdx) { - Integer oldNum = oldPinnedDialogNums.get(dialog.id); - if (oldNum != null) { - dialog.pinnedNum = oldNum; - } - } else { - long oldDid = oldPinnedOrder.get(newIdx); - Integer oldNum = oldPinnedDialogNums.get(oldDid); - if (oldNum != null) { - dialog.pinnedNum = oldNum; - } - } - } - if (dialog.pinnedNum == 0) { - dialog.pinnedNum = (totalPinnedCount - a) + maxPinnedNum; - } - } - - putDialogsInternal(dialogsRes, 0); - saveDiffParamsInternal(seq, newPts, date, qts); - - if (lastMessage != null && lastMessage.id != UserConfig.getInstance(currentAccount).dialogsLoadOffsetId) { - UserConfig.getInstance(currentAccount).totalDialogsLoadCount = dialogsRes.dialogs.size(); - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = lastMessage.id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = lastMessage.date; - if (lastMessage.to_id.channel_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = lastMessage.to_id.channel_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.chat_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = lastMessage.to_id.chat_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; - for (int a = 0; a < dialogsRes.chats.size(); a++) { - TLRPC.Chat chat = dialogsRes.chats.get(a); - if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; - break; - } - } - } else if (lastMessage.to_id.user_id != 0) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = lastMessage.to_id.user_id; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; - UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; - for (int a = 0; a < dialogsRes.users.size(); a++) { - TLRPC.User user = dialogsRes.users.get(a); - if (user.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId) { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = user.access_hash; - break; - } - } - } - } else { - UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; - } - UserConfig.getInstance(currentAccount).saveConfig(false); - MessagesController.getInstance(currentAccount).completeDialogsReset(dialogsRes, messagesCount, seq, newPts, date, qts, new_dialogs_dict, new_dialogMessage, lastMessage); - } catch (Exception e) { - FileLog.e(e); + for (int a = dialogsCount; a < dialogsRes.dialogs.size(); a++) { + TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(a); + orderArrayList.add(dialog.id); } + + SQLiteCursor cursor = database.queryFinalized("SELECT did, pinned FROM dialogs WHERE 1"); + while (cursor.next()) { + long did = cursor.longValue(0); + int pinnedNum = cursor.intValue(1); + int lower_id = (int) did; + if (lower_id != 0) { + dids.add(lower_id); + if (pinnedNum > 0) { + maxPinnedNum = Math.max(pinnedNum, maxPinnedNum); + oldPinnedDialogNums.put(did, pinnedNum); + oldPinnedOrder.add(did); + } + } + } + Collections.sort(oldPinnedOrder, (o1, o2) -> { + Integer val1 = oldPinnedDialogNums.get(o1); + Integer val2 = oldPinnedDialogNums.get(o2); + if (val1 < val2) { + return 1; + } else if (val1 > val2) { + return -1; + } + return 0; + }); + while (oldPinnedOrder.size() < totalPinnedCount) { + oldPinnedOrder.add(0, 0L); + } + cursor.dispose(); + String ids = "(" + TextUtils.join(",", dids) + ")"; + + database.beginTransaction(); + database.executeFast("DELETE FROM dialogs WHERE did IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM messages WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid IN " + ids).stepThis().dispose(); + database.commitTransaction(); + + for (int a = 0; a < totalPinnedCount; a++) { + TLRPC.TL_dialog dialog = dialogsRes.dialogs.get(dialogsCount + a); + int oldIdx = oldPinnedOrder.indexOf(dialog.id); + int newIdx = orderArrayList.indexOf(dialog.id); + if (oldIdx != -1 && newIdx != -1) { + if (oldIdx == newIdx) { + Integer oldNum = oldPinnedDialogNums.get(dialog.id); + if (oldNum != null) { + dialog.pinnedNum = oldNum; + } + } else { + long oldDid = oldPinnedOrder.get(newIdx); + Integer oldNum = oldPinnedDialogNums.get(oldDid); + if (oldNum != null) { + dialog.pinnedNum = oldNum; + } + } + } + if (dialog.pinnedNum == 0) { + dialog.pinnedNum = (totalPinnedCount - a) + maxPinnedNum; + } + } + + putDialogsInternal(dialogsRes, 0); + saveDiffParamsInternal(seq, newPts, date, qts); + + if (lastMessage != null && lastMessage.id != UserConfig.getInstance(currentAccount).dialogsLoadOffsetId) { + UserConfig.getInstance(currentAccount).totalDialogsLoadCount = dialogsRes.dialogs.size(); + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = lastMessage.id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetDate = lastMessage.date; + if (lastMessage.to_id.channel_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = lastMessage.to_id.channel_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.chat_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = lastMessage.to_id.chat_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.user_id != 0) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId = lastMessage.to_id.user_id; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChatId = 0; + UserConfig.getInstance(currentAccount).dialogsLoadOffsetChannelId = 0; + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User user = dialogsRes.users.get(a); + if (user.id == UserConfig.getInstance(currentAccount).dialogsLoadOffsetUserId) { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetAccess = user.access_hash; + break; + } + } + } + } else { + UserConfig.getInstance(currentAccount).dialogsLoadOffsetId = Integer.MAX_VALUE; + } + UserConfig.getInstance(currentAccount).saveConfig(false); + MessagesController.getInstance(currentAccount).completeDialogsReset(dialogsRes, messagesCount, seq, newPts, date, qts, new_dialogs_dict, new_dialogMessage, lastMessage); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -1958,247 +1794,288 @@ public class MessagesStorage { if (photos == null || photos.photos.isEmpty()) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); - for (TLRPC.Photo photo : photos.photos) { - if (photo instanceof TLRPC.TL_photoEmpty) { - continue; - } - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(photo.getObjectSize()); - photo.serializeToStream(data); - state.bindInteger(1, did); - state.bindLong(2, photo.id); - state.bindByteBuffer(3, data); - state.step(); - data.reuse(); + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); + for (TLRPC.Photo photo : photos.photos) { + if (photo instanceof TLRPC.TL_photoEmpty) { + continue; } - state.dispose(); - } catch (Exception e) { - FileLog.e(e); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(photo.getObjectSize()); + photo.serializeToStream(data); + state.bindInteger(1, did); + state.bindLong(2, photo.id); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); } + state.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void emptyMessagesMedia(final ArrayList mids) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - ArrayList filesToDelete = new ArrayList<>(); - final ArrayList messages = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message.media != null) { - if (message.media.document != null) { - File file = FileLoader.getPathToAttach(message.media.document, true); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - file = FileLoader.getPathToAttach(message.media.document.thumb, true); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - message.media.document = new TLRPC.TL_documentEmpty(); - } else if (message.media.photo != null) { - for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { - File file = FileLoader.getPathToAttach(photoSize, true); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - } - message.media.photo = new TLRPC.TL_photoEmpty(); - } else { - continue; + storageQueue.postRunnable(() -> { + try { + ArrayList filesToDelete = new ArrayList<>(); + final ArrayList messages = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message.media != null) { + if (message.media.document != null) { + File file = FileLoader.getPathToAttach(message.media.document, true); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); } - message.media.flags = message.media.flags &~ 1; - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.dialog_id = cursor.longValue(3); - messages.add(message); - } - } - } - cursor.dispose(); - if (!messages.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)"); - for (int a = 0; a < messages.size(); a++) { - TLRPC.Message message = messages.get(a); - - NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); - message.serializeToStream(data); - - state.requery(); - state.bindLong(1, message.id); - state.bindLong(2, message.dialog_id); - state.bindInteger(3, MessageObject.getUnreadFlags(message)); - state.bindInteger(4, message.send_state); - state.bindInteger(5, message.date); - state.bindByteBuffer(6, data); - state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); - state.bindInteger(8, message.ttl); - if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { - state.bindInteger(9, message.views); + file = FileLoader.getPathToAttach(message.media.document.thumb, true); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + message.media.document = new TLRPC.TL_documentEmpty(); + } else if (message.media.photo != null) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize, true); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + message.media.photo = new TLRPC.TL_photoEmpty(); } else { - state.bindInteger(9, getMessageMediaType(message)); + continue; } - state.bindInteger(10, 0); - state.bindInteger(11, message.mentioned ? 1 : 0); - state.step(); - - data.reuse(); + message.media.flags = message.media.flags &~ 1; + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = cursor.longValue(3); + messages.add(message); } - state.dispose(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < messages.size(); a++) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, messages.get(a)); - } - } - }); } - FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, 0); - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + if (!messages.isEmpty()) { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)"); + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + state.requery(); + state.bindLong(1, message.id); + state.bindLong(2, message.dialog_id); + state.bindInteger(3, MessageObject.getUnreadFlags(message)); + state.bindInteger(4, message.send_state); + state.bindInteger(5, message.date); + state.bindByteBuffer(6, data); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); + state.bindInteger(8, message.ttl); + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + state.bindInteger(9, message.views); + } else { + state.bindInteger(9, getMessageMediaType(message)); + } + state.bindInteger(10, 0); + state.bindInteger(11, message.mentioned ? 1 : 0); + state.step(); + + data.reuse(); + } + state.dispose(); + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < messages.size(); a++) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, messages.get(a)); + } + }); + } + FileLoader.getInstance(currentAccount).deleteFiles(filesToDelete, 0); + } catch (Exception e) { + FileLog.e(e); } }); } public void getNewTask(final ArrayList oldTask, final int channelId) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (oldTask != null) { - String ids = TextUtils.join(",", oldTask); - database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose(); - } - int date = 0; - int channelId = -1; - ArrayList arr = null; - SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)"); - while (cursor.next()) { - long mid = cursor.longValue(0); - if (channelId == -1) { - channelId = (int) (mid >> 32); - if (channelId < 0) { - channelId = 0; - } - } - date = cursor.intValue(1); - if (arr == null) { - arr = new ArrayList<>(); - } - arr.add((int) mid); - } - cursor.dispose(); - MessagesController.getInstance(currentAccount).processLoadedDeleteTask(date, arr, channelId); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (oldTask != null) { + String ids = TextUtils.join(",", oldTask); + database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose(); } + int date = 0; + int channelId1 = -1; + ArrayList arr = null; + SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)"); + while (cursor.next()) { + long mid = cursor.longValue(0); + if (channelId1 == -1) { + channelId1 = (int) (mid >> 32); + if (channelId1 < 0) { + channelId1 = 0; + } + } + date = cursor.intValue(1); + if (arr == null) { + arr = new ArrayList<>(); + } + arr.add((int) mid); + } + cursor.dispose(); + MessagesController.getInstance(currentAccount).processLoadedDeleteTask(date, arr, channelId1); + } catch (Exception e) { + FileLog.e(e); } }); } public void markMentionMessageAsRead(final int messageId, final int channelId, final long did) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - long mid = messageId; - if (channelId != 0) { - mid |= ((long) channelId) << 32; - } - - database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE mid = %d", mid)).stepThis().dispose(); - - SQLiteCursor cursor = database.queryFinalized("SELECT unread_count_i FROM dialogs WHERE did = " + did); - int old_mentions_count = 0; - if (cursor.next()) { - old_mentions_count = Math.max(0, cursor.intValue(0) - 1); - } - cursor.dispose(); - database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", old_mentions_count, did)).stepThis().dispose(); - LongSparseArray sparseArray = new LongSparseArray<>(1); - sparseArray.put(did, old_mentions_count); - MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + long mid = messageId; + if (channelId != 0) { + mid |= ((long) channelId) << 32; } + + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE mid = %d", mid)).stepThis().dispose(); + + SQLiteCursor cursor = database.queryFinalized("SELECT unread_count_i FROM dialogs WHERE did = " + did); + int old_mentions_count = 0; + if (cursor.next()) { + old_mentions_count = Math.max(0, cursor.intValue(0) - 1); + } + cursor.dispose(); + database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", old_mentions_count, did)).stepThis().dispose(); + LongSparseArray sparseArray = new LongSparseArray<>(1); + sparseArray.put(did, old_mentions_count); + MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); + } catch (Exception e) { + FileLog.e(e); } }); } public void markMessageAsMention(final long mid) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast(String.format(Locale.US, "UPDATE messages SET mention = 1, read_state = read_state & ~2 WHERE mid = %d", mid)).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast(String.format(Locale.US, "UPDATE messages SET mention = 1, read_state = read_state & ~2 WHERE mid = %d", mid)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } public void resetMentionsCount(final long did, final int count) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (count == 0) { - database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", did)).stepThis().dispose(); - } - database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", count, did)).stepThis().dispose(); - LongSparseArray sparseArray = new LongSparseArray<>(1); - sparseArray.put(did, count); - MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (count == 0) { + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", did)).stepThis().dispose(); } + database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", count, did)).stepThis().dispose(); + LongSparseArray sparseArray = new LongSparseArray<>(1); + sparseArray.put(did, count); + MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); + } catch (Exception e) { + FileLog.e(e); } }); } public void createTaskForMid(final int messageId, final int channelId, final int time, final int readTime, final int ttl, final boolean inner) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int minDate = (time > readTime ? time : readTime) + ttl; - SparseArray> messages = new SparseArray<>(); - final ArrayList midsArray = new ArrayList<>(); + storageQueue.postRunnable(() -> { + try { + int minDate = (time > readTime ? time : readTime) + ttl; + SparseArray> messages = new SparseArray<>(); + final ArrayList midsArray = new ArrayList<>(); - long mid = messageId; - if (channelId != 0) { - mid |= ((long) channelId) << 32; + long mid = messageId; + if (channelId != 0) { + mid |= ((long) channelId) << 32; + } + midsArray.add(mid); + messages.put(minDate, midsArray); + + AndroidUtilities.runOnUIThread(() -> { + if (!inner) { + markMessagesContentAsRead(midsArray, 0); } - midsArray.add(mid); - messages.put(minDate, midsArray); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, midsArray); + }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!inner) { - markMessagesContentAsRead(midsArray, 0); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, midsArray); - } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); + for (int a = 0; a < messages.size(); a++) { + int key = messages.keyAt(a); + ArrayList arr = messages.get(key); + for (int b = 0; b < arr.size(); b++) { + state.requery(); + state.bindLong(1, arr.get(b)); + state.bindInteger(2, key); + state.step(); + } + } + state.dispose(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid = %d", mid)).stepThis().dispose(); + MessagesController.getInstance(currentAccount).didAddedNewTask(minDate, messages); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void createTaskForSecretChat(final int chatId, final int time, final int readTime, final int isOut, final ArrayList random_ids) { + storageQueue.postRunnable(() -> { + try { + int minDate = Integer.MAX_VALUE; + SparseArray> messages = new SparseArray<>(); + final ArrayList midsArray = new ArrayList<>(); + StringBuilder mids = new StringBuilder(); + SQLiteCursor cursor; + if (random_ids == null) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state != 0 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long) chatId) << 32, isOut, time)); + } else { + String ids = TextUtils.join(",", random_ids); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids)); + } + while (cursor.next()) { + int ttl = cursor.intValue(1); + long mid = cursor.intValue(0); + if (random_ids != null) { + midsArray.add(mid); + } + if (ttl <= 0) { + continue; + } + int date = (time > readTime ? time : readTime) + ttl; + minDate = Math.min(minDate, date); + ArrayList arr = messages.get(date); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(date, arr); + } + if (mids.length() != 0) { + mids.append(","); + } + mids.append(mid); + arr.add(mid); + } + cursor.dispose(); + + if (random_ids != null) { + AndroidUtilities.runOnUIThread(() -> { + markMessagesContentAsRead(midsArray, 0); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, midsArray); }); + } + if (messages.size() != 0) { + database.beginTransaction(); SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); for (int a = 0; a < messages.size(); a++) { int key = messages.keyAt(a); @@ -2211,86 +2088,12 @@ public class MessagesStorage { } } state.dispose(); - database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid = %d", mid)).stepThis().dispose(); + database.commitTransaction(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose(); MessagesController.getInstance(currentAccount).didAddedNewTask(minDate, messages); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void createTaskForSecretChat(final int chatId, final int time, final int readTime, final int isOut, final ArrayList random_ids) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int minDate = Integer.MAX_VALUE; - SparseArray> messages = new SparseArray<>(); - final ArrayList midsArray = new ArrayList<>(); - StringBuilder mids = new StringBuilder(); - SQLiteCursor cursor; - if (random_ids == null) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state != 0 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long) chatId) << 32, isOut, time)); - } else { - String ids = TextUtils.join(",", random_ids); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids)); - } - while (cursor.next()) { - int ttl = cursor.intValue(1); - long mid = cursor.intValue(0); - if (random_ids != null) { - midsArray.add(mid); - } - if (ttl <= 0) { - continue; - } - int date = (time > readTime ? time : readTime) + ttl; - minDate = Math.min(minDate, date); - ArrayList arr = messages.get(date); - if (arr == null) { - arr = new ArrayList<>(); - messages.put(date, arr); - } - if (mids.length() != 0) { - mids.append(","); - } - mids.append(mid); - arr.add(mid); - } - cursor.dispose(); - - if (random_ids != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - markMessagesContentAsRead(midsArray, 0); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesReadContent, midsArray); - } - }); - } - - if (messages.size() != 0) { - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); - for (int a = 0; a < messages.size(); a++) { - int key = messages.keyAt(a); - ArrayList arr = messages.get(key); - for (int b = 0; b < arr.size(); b++) { - state.requery(); - state.bindLong(1, arr.get(b)); - state.bindInteger(2, key); - state.step(); - } - } - state.dispose(); - database.commitTransaction(); - database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose(); - MessagesController.getInstance(currentAccount).didAddedNewTask(minDate, messages); - } - } catch (Exception e) { - FileLog.e(e); } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -2446,12 +2249,7 @@ public class MessagesStorage { return; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - updateDialogsWithReadMessagesInternal(null, inbox, outbox, mentions); - } - }); + storageQueue.postRunnable(() -> updateDialogsWithReadMessagesInternal(null, inbox, outbox, mentions)); } else { updateDialogsWithReadMessagesInternal(null, inbox, outbox, mentions); } @@ -2461,208 +2259,25 @@ public class MessagesStorage { if (participants == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + participants.chat_id); - TLRPC.ChatFull info = null; - ArrayList loadedUsers = new ArrayList<>(); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); - } - } - cursor.dispose(); - if (info instanceof TLRPC.TL_chatFull) { - info.participants = participants; - final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); - } - }); - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); - info.serializeToStream(data); - state.bindInteger(1, info.id); - state.bindByteBuffer(2, data); - state.bindInteger(3, info.pinned_msg_id); - state.step(); - state.dispose(); + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + participants.chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + info.pinned_msg_id = cursor.intValue(1); } - } catch (Exception e) { - FileLog.e(e); } - } - }); - } + cursor.dispose(); + if (info instanceof TLRPC.TL_chatFull) { + info.participants = participants; + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null)); - public void loadChannelAdmins(final int chatId) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM channel_admins WHERE did = " + chatId); - ArrayList ids = new ArrayList<>(); - while (cursor.next()) { - ids.add(cursor.intValue(0)); - } - cursor.dispose(); - MessagesController.getInstance(currentAccount).processLoadedChannelAdmins(ids, chatId, true); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void putChannelAdmins(final int chatId, final ArrayList ids) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM channel_admins WHERE did = " + chatId).stepThis().dispose(); - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_admins VALUES(?, ?)"); - int date = (int) (System.currentTimeMillis() / 1000); - for (int a = 0; a < ids.size(); a++) { - state.requery(); - state.bindInteger(1, chatId); - state.bindInteger(2, ids.get(a)); - state.step(); - } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void updateChannelUsers(final int channel_id, final ArrayList participants) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - long did = -channel_id; - database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_users_v2 VALUES(?, ?, ?, ?)"); - NativeByteBuffer data; - int date = (int) (System.currentTimeMillis() / 1000); - for (int a = 0; a < participants.size(); a++) { - TLRPC.ChannelParticipant participant = participants.get(a); - state.requery(); - state.bindLong(1, did); - state.bindInteger(2, participant.user_id); - state.bindInteger(3, date); - data = new NativeByteBuffer(participant.getObjectSize()); - participant.serializeToStream(data); - state.bindByteBuffer(4, data); - data.reuse(); - state.step(); - date--; - } - state.dispose(); - database.commitTransaction(); - loadChatInfo(channel_id, null, false, true); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void saveBotCache(final String key, final TLObject result) { - if (result == null || TextUtils.isEmpty(key)) { - return; - } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int currentDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - if (result instanceof TLRPC.TL_messages_botCallbackAnswer) { - currentDate += ((TLRPC.TL_messages_botCallbackAnswer) result).cache_time; - } else if (result instanceof TLRPC.TL_messages_botResults) { - currentDate += ((TLRPC.TL_messages_botResults) result).cache_time; - } - SQLitePreparedStatement state = database.executeFast("REPLACE INTO botcache VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize()); - result.serializeToStream(data); - state.bindString(1, key); - state.bindInteger(2, currentDate); - state.bindByteBuffer(3, data); - state.step(); - state.dispose(); - data.reuse(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void getBotCache(final String key, final RequestDelegate requestDelegate) { - if (key == null || requestDelegate == null) { - return; - } - final int currentDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - TLObject result = null; - try { - database.executeFast("DELETE FROM botcache WHERE date < " + currentDate).stepThis().dispose(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM botcache WHERE id = '%s'", key)); - if (cursor.next()) { - try { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - int constructor = data.readInt32(false); - if (constructor == TLRPC.TL_messages_botCallbackAnswer.constructor) { - result = TLRPC.TL_messages_botCallbackAnswer.TLdeserialize(data, constructor, false); - } else { - result = TLRPC.messages_BotResults.TLdeserialize(data, constructor, false); - } - data.reuse(); - } - } catch (Exception e) { - FileLog.e(e); - } - } - cursor.dispose(); - } catch (Exception e) { - FileLog.e(e); - } finally { - requestDelegate.run(result, null); - } - } - }); - - } - - public void updateChatInfo(final TLRPC.ChatFull info, final boolean ifExist) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (ifExist) { - SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM chat_settings_v2 WHERE uid = " + info.id); - boolean exist = cursor.next(); - cursor.dispose(); - if (!exist) { - return; - } - } SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); info.serializeToStream(data); @@ -2672,177 +2287,318 @@ public class MessagesStorage { state.step(); state.dispose(); data.reuse(); - - if (info instanceof TLRPC.TL_channelFull) { - SQLiteCursor cursor = database.queryFinalized("SELECT date, pts, last_mid, inbox_max, outbox_max, pinned, unread_count_i, flags FROM dialogs WHERE did = " + (-info.id)); - if (cursor.next()) { - int inbox_max = cursor.intValue(3); - if (inbox_max < info.read_inbox_max_id) { - /*int inbox_diff = info.read_inbox_max_id - inbox_max; - if (inbox_diff < info.unread_count) { - info.unread_count = inbox_diff; - }*/ - int dialog_date = cursor.intValue(0); - int pts = cursor.intValue(1); - long last_mid = cursor.longValue(2); - int outbox_max = cursor.intValue(4); - int pinned = cursor.intValue(5); - int mentions = cursor.intValue(6); - int flags = cursor.intValue(7); - - state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - state.bindLong(1, -info.id); - state.bindInteger(2, dialog_date); - state.bindInteger(3, info.unread_count); - state.bindLong(4, last_mid); - state.bindInteger(5, info.read_inbox_max_id); - state.bindInteger(6, Math.max(outbox_max, info.read_outbox_max_id)); - state.bindLong(7, 0); - state.bindInteger(8, mentions); - state.bindInteger(9, pts); - state.bindInteger(10, 0); - state.bindInteger(11, pinned); - state.bindInteger(12, flags); - state.step(); - state.dispose(); - } - } - cursor.dispose(); - } - } catch (Exception e) { - FileLog.e(e); } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void loadChannelAdmins(final int chatId) { + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM channel_admins WHERE did = " + chatId); + ArrayList ids = new ArrayList<>(); + while (cursor.next()) { + ids.add(cursor.intValue(0)); + } + cursor.dispose(); + MessagesController.getInstance(currentAccount).processLoadedChannelAdmins(ids, chatId, true); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void putChannelAdmins(final int chatId, final ArrayList ids) { + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM channel_admins WHERE did = " + chatId).stepThis().dispose(); + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_admins VALUES(?, ?)"); + int date = (int) (System.currentTimeMillis() / 1000); + for (int a = 0; a < ids.size(); a++) { + state.requery(); + state.bindInteger(1, chatId); + state.bindInteger(2, ids.get(a)); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void updateChannelUsers(final int channel_id, final ArrayList participants) { + storageQueue.postRunnable(() -> { + try { + long did = -channel_id; + database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_users_v2 VALUES(?, ?, ?, ?)"); + NativeByteBuffer data; + int date = (int) (System.currentTimeMillis() / 1000); + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChannelParticipant participant = participants.get(a); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, participant.user_id); + state.bindInteger(3, date); + data = new NativeByteBuffer(participant.getObjectSize()); + participant.serializeToStream(data); + state.bindByteBuffer(4, data); + data.reuse(); + state.step(); + date--; + } + state.dispose(); + database.commitTransaction(); + loadChatInfo(channel_id, null, false, true); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void saveBotCache(final String key, final TLObject result) { + if (result == null || TextUtils.isEmpty(key)) { + return; + } + storageQueue.postRunnable(() -> { + try { + int currentDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + if (result instanceof TLRPC.TL_messages_botCallbackAnswer) { + currentDate += ((TLRPC.TL_messages_botCallbackAnswer) result).cache_time; + } else if (result instanceof TLRPC.TL_messages_botResults) { + currentDate += ((TLRPC.TL_messages_botResults) result).cache_time; + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO botcache VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize()); + result.serializeToStream(data); + state.bindString(1, key); + state.bindInteger(2, currentDate); + state.bindByteBuffer(3, data); + state.step(); + state.dispose(); + data.reuse(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void getBotCache(final String key, final RequestDelegate requestDelegate) { + if (key == null || requestDelegate == null) { + return; + } + final int currentDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + storageQueue.postRunnable(() -> { + TLObject result = null; + try { + database.executeFast("DELETE FROM botcache WHERE date < " + currentDate).stepThis().dispose(); + SQLiteCursor cursor = database.queryFinalized( "SELECT data FROM botcache WHERE id = ?", key); + if (cursor.next()) { + try { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + int constructor = data.readInt32(false); + if (constructor == TLRPC.TL_messages_botCallbackAnswer.constructor) { + result = TLRPC.TL_messages_botCallbackAnswer.TLdeserialize(data, constructor, false); + } else { + result = TLRPC.messages_BotResults.TLdeserialize(data, constructor, false); + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + cursor.dispose(); + } catch (Exception e) { + FileLog.e(e); + } finally { + requestDelegate.run(result, null); + } + }); + + } + + public void updateChatInfo(final TLRPC.ChatFull info, final boolean ifExist) { + storageQueue.postRunnable(() -> { + try { + if (ifExist) { + SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM chat_settings_v2 WHERE uid = " + info.id); + boolean exist = cursor.next(); + cursor.dispose(); + if (!exist) { + return; + } + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, info.id); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + + if (info instanceof TLRPC.TL_channelFull) { + SQLiteCursor cursor = database.queryFinalized("SELECT date, pts, last_mid, inbox_max, outbox_max, pinned, unread_count_i, flags FROM dialogs WHERE did = " + (-info.id)); + if (cursor.next()) { + int inbox_max = cursor.intValue(3); + if (inbox_max < info.read_inbox_max_id) { + /*int inbox_diff = info.read_inbox_max_id - inbox_max; + if (inbox_diff < info.unread_count) { + info.unread_count = inbox_diff; + }*/ + int dialog_date = cursor.intValue(0); + int pts = cursor.intValue(1); + long last_mid = cursor.longValue(2); + int outbox_max = cursor.intValue(4); + int pinned = cursor.intValue(5); + int mentions = cursor.intValue(6); + int flags = cursor.intValue(7); + + state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state.bindLong(1, -info.id); + state.bindInteger(2, dialog_date); + state.bindInteger(3, info.unread_count); + state.bindLong(4, last_mid); + state.bindInteger(5, info.read_inbox_max_id); + state.bindInteger(6, Math.max(outbox_max, info.read_outbox_max_id)); + state.bindLong(7, 0); + state.bindInteger(8, mentions); + state.bindInteger(9, pts); + state.bindInteger(10, 0); + state.bindInteger(11, pinned); + state.bindInteger(12, flags); + state.step(); + state.dispose(); + } + } + cursor.dispose(); + } + } catch (Exception e) { + FileLog.e(e); } }); } public void updateChannelPinnedMessage(final int channelId, final int messageId) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + channelId); - TLRPC.ChatFull info = null; - ArrayList loadedUsers = new ArrayList<>(); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); - } - } - cursor.dispose(); - if (info instanceof TLRPC.TL_channelFull) { - info.pinned_msg_id = messageId; - info.flags |= 32; - - final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); - } - }); - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); - info.serializeToStream(data); - state.bindInteger(1, channelId); - state.bindByteBuffer(2, data); - state.bindInteger(3, info.pinned_msg_id); - state.step(); - state.dispose(); + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + channelId); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + info.pinned_msg_id = cursor.intValue(1); } - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + if (info instanceof TLRPC.TL_channelFull) { + info.pinned_msg_id = messageId; + info.flags |= 32; + + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null)); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, channelId); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e(e); } }); } public void updateChatInfo(final int chat_id, final int user_id, final int what, final int invited_id, final int version) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); - TLRPC.ChatFull info = null; - ArrayList loadedUsers = new ArrayList<>(); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); - } - } - cursor.dispose(); - if (info instanceof TLRPC.TL_chatFull) { - if (what == 1) { - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant participant = info.participants.participants.get(a); - if (participant.user_id == user_id) { - info.participants.participants.remove(a); - break; - } - } - } else if (what == 0) { - for (TLRPC.ChatParticipant part : info.participants.participants) { - if (part.user_id == user_id) { - return; - } - } - TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant(); - participant.user_id = user_id; - participant.inviter_id = invited_id; - participant.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - info.participants.participants.add(participant); - } else if (what == 2) { - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant participant = info.participants.participants.get(a); - if (participant.user_id == user_id) { - TLRPC.ChatParticipant newParticipant; - if (invited_id == 1) { - newParticipant = new TLRPC.TL_chatParticipantAdmin(); - newParticipant.user_id = participant.user_id; - newParticipant.date = participant.date; - newParticipant.inviter_id = participant.inviter_id; - } else { - newParticipant = new TLRPC.TL_chatParticipant(); - newParticipant.user_id = participant.user_id; - newParticipant.date = participant.date; - newParticipant.inviter_id = participant.inviter_id; - } - info.participants.participants.set(a, newParticipant); - break; - } - } - } - info.participants.version = version; - - final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); - } - }); - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); - info.serializeToStream(data); - state.bindInteger(1, chat_id); - state.bindByteBuffer(2, data); - state.bindInteger(3, info.pinned_msg_id); - state.step(); - state.dispose(); + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + info.pinned_msg_id = cursor.intValue(1); } - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + if (info instanceof TLRPC.TL_chatFull) { + if (what == 1) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + if (participant.user_id == user_id) { + info.participants.participants.remove(a); + break; + } + } + } else if (what == 0) { + for (TLRPC.ChatParticipant part : info.participants.participants) { + if (part.user_id == user_id) { + return; + } + } + TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant(); + participant.user_id = user_id; + participant.inviter_id = invited_id; + participant.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + info.participants.participants.add(participant); + } else if (what == 2) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + if (participant.user_id == user_id) { + TLRPC.ChatParticipant newParticipant; + if (invited_id == 1) { + newParticipant = new TLRPC.TL_chatParticipantAdmin(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } else { + newParticipant = new TLRPC.TL_chatParticipant(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } + info.participants.participants.set(a, newParticipant); + break; + } + } + } + info.participants.version = version; + + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null)); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, chat_id); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -2850,32 +2606,29 @@ public class MessagesStorage { public boolean isMigratedChat(final int chat_id) { final CountDownLatch countDownLatch = new CountDownLatch(1); final boolean result[] = new boolean[1]; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id); - TLRPC.ChatFull info = null; - ArrayList loadedUsers = new ArrayList<>(); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - } - } - cursor.dispose(); - result[0] = info instanceof TLRPC.TL_channelFull && info.migrated_from_chat_id != 0; - if (countDownLatch != null) { - countDownLatch.countDown(); - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (countDownLatch != null) { - countDownLatch.countDown(); + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); } } + cursor.dispose(); + result[0] = info instanceof TLRPC.TL_channelFull && info.migrated_from_chat_id != 0; + if (countDownLatch != null) { + countDownLatch.countDown(); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (countDownLatch != null) { + countDownLatch.countDown(); + } } }); try { @@ -2887,181 +2640,175 @@ public class MessagesStorage { } public void loadChatInfo(final int chat_id, final CountDownLatch countDownLatch, final boolean force, final boolean byChannelUsers) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessageObject pinnedMessageObject = null; - TLRPC.ChatFull info = null; - ArrayList loadedUsers = new ArrayList<>(); - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); + storageQueue.postRunnable(() -> { + MessageObject pinnedMessageObject = null; + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + info.pinned_msg_id = cursor.intValue(1); + } + } + cursor.dispose(); + + if (info instanceof TLRPC.TL_chatFull) { + StringBuilder usersToLoad = new StringBuilder(); + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant c = info.participants.participants.get(a); + if (usersToLoad.length() != 0) { + usersToLoad.append(","); + } + usersToLoad.append(c.user_id); + } + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), loadedUsers); + } + } else if (info instanceof TLRPC.TL_channelFull) { + cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chat_id) + " ORDER BY cu.date DESC"); + info.participants = new TLRPC.TL_chatParticipants(); + while (cursor.next()) { + try { + TLRPC.User user = null; + TLRPC.ChannelParticipant participant = null; + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + } + data = cursor.byteBufferValue(2); + if (data != null) { + participant = TLRPC.ChannelParticipant.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + } + if (user != null && participant != null) { + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + loadedUsers.add(user); + participant.date = cursor.intValue(3); + TLRPC.TL_chatChannelParticipant chatChannelParticipant = new TLRPC.TL_chatChannelParticipant(); + chatChannelParticipant.user_id = participant.user_id; + chatChannelParticipant.date = participant.date; + chatChannelParticipant.inviter_id = participant.inviter_id; + chatChannelParticipant.channelParticipant = participant; + info.participants.participants.add(chatChannelParticipant); + } + } catch (Exception e) { + FileLog.e(e); } } cursor.dispose(); - - if (info instanceof TLRPC.TL_chatFull) { - StringBuilder usersToLoad = new StringBuilder(); - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant c = info.participants.participants.get(a); - if (usersToLoad.length() != 0) { - usersToLoad.append(","); - } - usersToLoad.append(c.user_id); - } + StringBuilder usersToLoad = new StringBuilder(); + for (int a = 0; a < info.bot_info.size(); a++) { + TLRPC.BotInfo botInfo = info.bot_info.get(a); if (usersToLoad.length() != 0) { - getUsersInternal(usersToLoad.toString(), loadedUsers); - } - } else if (info instanceof TLRPC.TL_channelFull) { - cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chat_id) + " ORDER BY cu.date DESC"); - info.participants = new TLRPC.TL_chatParticipants(); - while (cursor.next()) { - try { - TLRPC.User user = null; - TLRPC.ChannelParticipant participant = null; - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - } - data = cursor.byteBufferValue(2); - if (data != null) { - participant = TLRPC.ChannelParticipant.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - } - if (user != null && participant != null) { - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - loadedUsers.add(user); - participant.date = cursor.intValue(3); - TLRPC.TL_chatChannelParticipant chatChannelParticipant = new TLRPC.TL_chatChannelParticipant(); - chatChannelParticipant.user_id = participant.user_id; - chatChannelParticipant.date = participant.date; - chatChannelParticipant.inviter_id = participant.inviter_id; - chatChannelParticipant.channelParticipant = participant; - info.participants.participants.add(chatChannelParticipant); - } - } catch (Exception e) { - FileLog.e(e); - } - } - cursor.dispose(); - StringBuilder usersToLoad = new StringBuilder(); - for (int a = 0; a < info.bot_info.size(); a++) { - TLRPC.BotInfo botInfo = info.bot_info.get(a); - if (usersToLoad.length() != 0) { - usersToLoad.append(","); - } - usersToLoad.append(botInfo.user_id); - } - if (usersToLoad.length() != 0) { - getUsersInternal(usersToLoad.toString(), loadedUsers); + usersToLoad.append(","); } + usersToLoad.append(botInfo.user_id); } - if (countDownLatch != null) { - countDownLatch.countDown(); - } - if (info instanceof TLRPC.TL_channelFull && info.pinned_msg_id != 0) { - pinnedMessageObject = DataQuery.getInstance(currentAccount).loadPinnedMessage(chat_id, info.pinned_msg_id, false); - } - } catch (Exception e) { - FileLog.e(e); - } finally { - MessagesController.getInstance(currentAccount).processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject); - if (countDownLatch != null) { - countDownLatch.countDown(); + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), loadedUsers); } } + if (countDownLatch != null) { + countDownLatch.countDown(); + } + if (info instanceof TLRPC.TL_channelFull && info.pinned_msg_id != 0) { + pinnedMessageObject = DataQuery.getInstance(currentAccount).loadPinnedMessage(chat_id, info.pinned_msg_id, false); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + MessagesController.getInstance(currentAccount).processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject); + if (countDownLatch != null) { + countDownLatch.countDown(); + } } }); } public void processPendingRead(final long dialog_id, final long maxPositiveId, final long maxNegativeId, final int max_date, final boolean isChannel) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - long currentMaxId = 0; - int unreadCount = 0; - long last_mid = 0; - SQLiteCursor cursor = database.queryFinalized("SELECT unread_count, inbox_max, last_mid FROM dialogs WHERE did = " + dialog_id); - if (cursor.next()) { - unreadCount = cursor.intValue(0); - currentMaxId = cursor.intValue(1); - last_mid = cursor.longValue(2); - } - cursor.dispose(); + storageQueue.postRunnable(() -> { + try { + long currentMaxId = 0; + int unreadCount = 0; + long last_mid = 0; + SQLiteCursor cursor = database.queryFinalized("SELECT unread_count, inbox_max, last_mid FROM dialogs WHERE did = " + dialog_id); + if (cursor.next()) { + unreadCount = cursor.intValue(0); + currentMaxId = cursor.intValue(1); + last_mid = cursor.longValue(2); + } + cursor.dispose(); - database.beginTransaction(); - SQLitePreparedStatement state; + database.beginTransaction(); + SQLitePreparedStatement state; - int lower_id = (int) dialog_id; + int lower_id = (int) dialog_id; - if (lower_id != 0) { - currentMaxId = Math.max(currentMaxId, (int) maxPositiveId); - if (isChannel) { - currentMaxId |= ((long) -lower_id) << 32; - } - - state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid <= ? AND read_state IN(0,2) AND out = 0"); - state.requery(); - state.bindLong(1, dialog_id); - state.bindLong(2, currentMaxId); - state.step(); - state.dispose(); - - if (currentMaxId >= last_mid) { - unreadCount = 0; - } else { - int updatedCount = 0; - cursor = database.queryFinalized("SELECT changes()"); - if (cursor.next()) { - updatedCount = cursor.intValue(0); - } - cursor.dispose(); - unreadCount = Math.max(0, unreadCount - updatedCount); - } - } else { - currentMaxId = (int) maxNegativeId; - - state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid >= ? AND read_state IN(0,2) AND out = 0"); - state.requery(); - state.bindLong(1, dialog_id); - state.bindLong(2, currentMaxId); - state.step(); - state.dispose(); - - if (currentMaxId <= last_mid) { - unreadCount = 0; - } else { - int updatedCount = 0; - cursor = database.queryFinalized("SELECT changes()"); - if (cursor.next()) { - updatedCount = cursor.intValue(0); - } - cursor.dispose(); - unreadCount = Math.max(0, unreadCount - updatedCount); - } + if (lower_id != 0) { + currentMaxId = Math.max(currentMaxId, (int) maxPositiveId); + if (isChannel) { + currentMaxId |= ((long) -lower_id) << 32; } - state = database.executeFast("UPDATE dialogs SET unread_count = ?, inbox_max = ? WHERE did = ?"); + state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid <= ? AND read_state IN(0,2) AND out = 0"); state.requery(); - state.bindInteger(1, unreadCount); - state.bindInteger(2, (int) currentMaxId); - state.bindLong(3, dialog_id); + state.bindLong(1, dialog_id); + state.bindLong(2, currentMaxId); state.step(); state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); + if (currentMaxId >= last_mid) { + unreadCount = 0; + } else { + int updatedCount = 0; + cursor = database.queryFinalized("SELECT changes()"); + if (cursor.next()) { + updatedCount = cursor.intValue(0); + } + cursor.dispose(); + unreadCount = Math.max(0, unreadCount - updatedCount); + } + } else { + currentMaxId = (int) maxNegativeId; + + state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid >= ? AND read_state IN(0,2) AND out = 0"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindLong(2, currentMaxId); + state.step(); + state.dispose(); + + if (currentMaxId <= last_mid) { + unreadCount = 0; + } else { + int updatedCount = 0; + cursor = database.queryFinalized("SELECT changes()"); + if (cursor.next()) { + updatedCount = cursor.intValue(0); + } + cursor.dispose(); + unreadCount = Math.max(0, unreadCount - updatedCount); + } } + + state = database.executeFast("UPDATE dialogs SET unread_count = ?, inbox_max = ? WHERE did = ?"); + state.requery(); + state.bindInteger(1, unreadCount); + state.bindInteger(2, (int) currentMaxId); + state.bindLong(3, dialog_id); + state.step(); + state.dispose(); + + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3071,27 +2818,24 @@ public class MessagesStorage { return; } final ArrayList contactsCopy = new ArrayList<>(contacts); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (deleteAll) { - database.executeFast("DELETE FROM contacts WHERE 1").stepThis().dispose(); - } - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO contacts VALUES(?, ?)"); - for (int a = 0; a < contactsCopy.size(); a++) { - TLRPC.TL_contact contact = contactsCopy.get(a); - state.requery(); - state.bindInteger(1, contact.user_id); - state.bindInteger(2, contact.mutual ? 1 : 0); - state.step(); - } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (deleteAll) { + database.executeFast("DELETE FROM contacts WHERE 1").stepThis().dispose(); } + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO contacts VALUES(?, ?)"); + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.TL_contact contact = contactsCopy.get(a); + state.requery(); + state.bindInteger(1, contact.user_id); + state.bindInteger(2, contact.mutual ? 1 : 0); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3100,15 +2844,12 @@ public class MessagesStorage { if (uids == null || uids.isEmpty()) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - String ids = TextUtils.join(",", uids); - database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + String ids = TextUtils.join(",", uids); + database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3117,19 +2858,16 @@ public class MessagesStorage { if (adds.length() == 0 && deletes.length() == 0) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (adds.length() != 0) { - database.executeFast(String.format(Locale.US, "UPDATE user_phones_v7 SET deleted = 0 WHERE sphone IN(%s)", adds)).stepThis().dispose(); - } - if (deletes.length() != 0) { - database.executeFast(String.format(Locale.US, "UPDATE user_phones_v7 SET deleted = 1 WHERE sphone IN(%s)", deletes)).stepThis().dispose(); - } - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (adds.length() != 0) { + database.executeFast(String.format(Locale.US, "UPDATE user_phones_v7 SET deleted = 0 WHERE sphone IN(%s)", adds)).stepThis().dispose(); } + if (deletes.length() != 0) { + database.executeFast(String.format(Locale.US, "UPDATE user_phones_v7 SET deleted = 1 WHERE sphone IN(%s)", deletes)).stepThis().dispose(); + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3138,177 +2876,93 @@ public class MessagesStorage { if (contactHashMap == null || contactHashMap.isEmpty() && !migrate && !delete) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (BuildVars.LOGS_ENABLED) { - FileLog.d(currentAccount + " save contacts to db " + contactHashMap.size()); - } - database.executeFast("DELETE FROM user_contacts_v7 WHERE 1").stepThis().dispose(); - database.executeFast("DELETE FROM user_phones_v7 WHERE 1").stepThis().dispose(); - - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_contacts_v7 VALUES(?, ?, ?, ?, ?)"); - SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO user_phones_v7 VALUES(?, ?, ?, ?)"); - for (HashMap.Entry entry : contactHashMap.entrySet()) { - ContactsController.Contact contact = entry.getValue(); - if (contact.phones.isEmpty() || contact.shortPhones.isEmpty()) { - continue; - } - state.requery(); - state.bindString(1, contact.key); - state.bindInteger(2, contact.contact_id); - state.bindString(3, contact.first_name); - state.bindString(4, contact.last_name); - state.bindInteger(5, contact.imported); - state.step(); - for (int a = 0; a < contact.phones.size(); a++) { - state2.requery(); - state2.bindString(1, contact.key); - state2.bindString(2, contact.phones.get(a)); - state2.bindString(3, contact.shortPhones.get(a)); - state2.bindInteger(4, contact.phoneDeleted.get(a)); - state2.step(); - } - } - state.dispose(); - state2.dispose(); - database.commitTransaction(); - if (migrate) { - database.executeFast("DROP TABLE IF EXISTS user_contacts_v6;").stepThis().dispose(); - database.executeFast("DROP TABLE IF EXISTS user_phones_v6;").stepThis().dispose(); - getCachedPhoneBook(false); - } - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (BuildVars.LOGS_ENABLED) { + FileLog.d(currentAccount + " save contacts to db " + contactHashMap.size()); } + database.executeFast("DELETE FROM user_contacts_v7 WHERE 1").stepThis().dispose(); + database.executeFast("DELETE FROM user_phones_v7 WHERE 1").stepThis().dispose(); + + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_contacts_v7 VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO user_phones_v7 VALUES(?, ?, ?, ?)"); + for (HashMap.Entry entry : contactHashMap.entrySet()) { + ContactsController.Contact contact = entry.getValue(); + if (contact.phones.isEmpty() || contact.shortPhones.isEmpty()) { + continue; + } + state.requery(); + state.bindString(1, contact.key); + state.bindInteger(2, contact.contact_id); + state.bindString(3, contact.first_name); + state.bindString(4, contact.last_name); + state.bindInteger(5, contact.imported); + state.step(); + for (int a = 0; a < contact.phones.size(); a++) { + state2.requery(); + state2.bindString(1, contact.key); + state2.bindString(2, contact.phones.get(a)); + state2.bindString(3, contact.shortPhones.get(a)); + state2.bindInteger(4, contact.phoneDeleted.get(a)); + state2.step(); + } + } + state.dispose(); + state2.dispose(); + database.commitTransaction(); + if (migrate) { + database.executeFast("DROP TABLE IF EXISTS user_contacts_v6;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS user_phones_v6;").stepThis().dispose(); + getCachedPhoneBook(false); + } + } catch (Exception e) { + FileLog.e(e); } }); } public void getCachedPhoneBook(final boolean byError) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLiteCursor cursor = null; - try { - cursor = database.queryFinalized("SELECT name FROM sqlite_master WHERE type='table' AND name='user_contacts_v6'"); - boolean migrate = cursor.next(); - cursor.dispose(); - cursor = null; - if (migrate) { - int count = 16; - cursor = database.queryFinalized("SELECT COUNT(uid) FROM user_contacts_v6 WHERE 1"); - if (cursor.next()) { - count = Math.min(5000, cursor.intValue(0)); - } - cursor.dispose(); - - SparseArray contactHashMap = new SparseArray<>(count); - cursor = database.queryFinalized("SELECT us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v6 as us LEFT JOIN user_phones_v6 as up ON us.uid = up.uid WHERE 1"); - while (cursor.next()) { - int uid = cursor.intValue(0); - ContactsController.Contact contact = contactHashMap.get(uid); - if (contact == null) { - contact = new ContactsController.Contact(); - contact.first_name = cursor.stringValue(1); - contact.last_name = cursor.stringValue(2); - contact.imported = cursor.intValue(6); - if (contact.first_name == null) { - contact.first_name = ""; - } - if (contact.last_name == null) { - contact.last_name = ""; - } - contact.contact_id = uid; - contactHashMap.put(uid, contact); - } - String phone = cursor.stringValue(3); - if (phone == null) { - continue; - } - contact.phones.add(phone); - String sphone = cursor.stringValue(4); - if (sphone == null) { - continue; - } - if (sphone.length() == 8 && phone.length() != 8) { - sphone = PhoneFormat.stripExceptNumbers(phone); - } - contact.shortPhones.add(sphone); - contact.phoneDeleted.add(cursor.intValue(5)); - contact.phoneTypes.add(""); - if (contactHashMap.size() == 5000) { - break; - } - } - cursor.dispose(); - cursor = null; - ContactsController.getInstance(currentAccount).migratePhoneBookToV7(contactHashMap); - return; - } - } catch (Throwable e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } - } - - int count = 16; - int currentContactsCount = 0; - int start = 0; - try { - cursor = database.queryFinalized("SELECT COUNT(key) FROM user_contacts_v7 WHERE 1"); + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT name FROM sqlite_master WHERE type='table' AND name='user_contacts_v6'"); + boolean migrate = cursor.next(); + cursor.dispose(); + cursor = null; + if (migrate) { + int count = 16; + cursor = database.queryFinalized("SELECT COUNT(uid) FROM user_contacts_v6 WHERE 1"); if (cursor.next()) { - currentContactsCount = cursor.intValue(0); - count = Math.min(5000, currentContactsCount); - if (currentContactsCount > 5000) { - start = currentContactsCount - 5000; - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d(currentAccount + " current cached contacts count = " + currentContactsCount); - } + count = Math.min(5000, cursor.intValue(0)); } - } catch (Throwable e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } - } + cursor.dispose(); - HashMap contactHashMap = new HashMap<>(count); - try { - if (start != 0) { - cursor = database.queryFinalized("SELECT us.key, us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v7 as us LEFT JOIN user_phones_v7 as up ON us.key = up.key WHERE 1 LIMIT " + 0 + "," + currentContactsCount); - } else { - cursor = database.queryFinalized("SELECT us.key, us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v7 as us LEFT JOIN user_phones_v7 as up ON us.key = up.key WHERE 1"); - } + SparseArray contactHashMap = new SparseArray<>(count); + cursor = database.queryFinalized("SELECT us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v6 as us LEFT JOIN user_phones_v6 as up ON us.uid = up.uid WHERE 1"); while (cursor.next()) { - String key = cursor.stringValue(0); - ContactsController.Contact contact = contactHashMap.get(key); + int uid = cursor.intValue(0); + ContactsController.Contact contact = contactHashMap.get(uid); if (contact == null) { contact = new ContactsController.Contact(); - contact.contact_id = cursor.intValue(1); - contact.first_name = cursor.stringValue(2); - contact.last_name = cursor.stringValue(3); - contact.imported = cursor.intValue(7); + contact.first_name = cursor.stringValue(1); + contact.last_name = cursor.stringValue(2); + contact.imported = cursor.intValue(6); if (contact.first_name == null) { contact.first_name = ""; } if (contact.last_name == null) { contact.last_name = ""; } - contactHashMap.put(key, contact); + contact.contact_id = uid; + contactHashMap.put(uid, contact); } - String phone = cursor.stringValue(4); + String phone = cursor.stringValue(3); if (phone == null) { continue; } contact.phones.add(phone); - String sphone = cursor.stringValue(5); + String sphone = cursor.stringValue(4); if (sphone == null) { continue; } @@ -3316,7 +2970,7 @@ public class MessagesStorage { sphone = PhoneFormat.stripExceptNumbers(phone); } contact.shortPhones.add(sphone); - contact.phoneDeleted.add(cursor.intValue(6)); + contact.phoneDeleted.add(cursor.intValue(5)); contact.phoneTypes.add(""); if (contactHashMap.size() == 5000) { break; @@ -3324,161 +2978,233 @@ public class MessagesStorage { } cursor.dispose(); cursor = null; - } catch (Exception e) { - contactHashMap.clear(); - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); + ContactsController.getInstance(currentAccount).migratePhoneBookToV7(contactHashMap); + return; + } + } catch (Throwable e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + + int count = 16; + int currentContactsCount = 0; + int start = 0; + try { + cursor = database.queryFinalized("SELECT COUNT(key) FROM user_contacts_v7 WHERE 1"); + if (cursor.next()) { + currentContactsCount = cursor.intValue(0); + count = Math.min(5000, currentContactsCount); + if (currentContactsCount > 5000) { + start = currentContactsCount - 5000; + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d(currentAccount + " current cached contacts count = " + currentContactsCount); } } - ContactsController.getInstance(currentAccount).performSyncPhoneBook(contactHashMap, true, true, false, false, !byError, false); + } catch (Throwable e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } } + + HashMap contactHashMap = new HashMap<>(count); + try { + if (start != 0) { + cursor = database.queryFinalized("SELECT us.key, us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v7 as us LEFT JOIN user_phones_v7 as up ON us.key = up.key WHERE 1 LIMIT " + 0 + "," + currentContactsCount); + } else { + cursor = database.queryFinalized("SELECT us.key, us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted, us.imported FROM user_contacts_v7 as us LEFT JOIN user_phones_v7 as up ON us.key = up.key WHERE 1"); + } + while (cursor.next()) { + String key = cursor.stringValue(0); + ContactsController.Contact contact = contactHashMap.get(key); + if (contact == null) { + contact = new ContactsController.Contact(); + contact.contact_id = cursor.intValue(1); + contact.first_name = cursor.stringValue(2); + contact.last_name = cursor.stringValue(3); + contact.imported = cursor.intValue(7); + if (contact.first_name == null) { + contact.first_name = ""; + } + if (contact.last_name == null) { + contact.last_name = ""; + } + contactHashMap.put(key, contact); + } + String phone = cursor.stringValue(4); + if (phone == null) { + continue; + } + contact.phones.add(phone); + String sphone = cursor.stringValue(5); + if (sphone == null) { + continue; + } + if (sphone.length() == 8 && phone.length() != 8) { + sphone = PhoneFormat.stripExceptNumbers(phone); + } + contact.shortPhones.add(sphone); + contact.phoneDeleted.add(cursor.intValue(6)); + contact.phoneTypes.add(""); + if (contactHashMap.size() == 5000) { + break; + } + } + cursor.dispose(); + cursor = null; + } catch (Exception e) { + contactHashMap.clear(); + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + ContactsController.getInstance(currentAccount).performSyncPhoneBook(contactHashMap, true, true, false, false, !byError, false); }); } public void getContacts() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ArrayList contacts = new ArrayList<>(); - ArrayList users = new ArrayList<>(); - try { - SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1"); - StringBuilder uids = new StringBuilder(); - while (cursor.next()) { - int user_id = cursor.intValue(0); - TLRPC.TL_contact contact = new TLRPC.TL_contact(); - contact.user_id = user_id; - contact.mutual = cursor.intValue(1) == 1; - if (uids.length() != 0) { - uids.append(","); - } - contacts.add(contact); - uids.append(contact.user_id); - } - cursor.dispose(); - + storageQueue.postRunnable(() -> { + ArrayList contacts = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + try { + SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1"); + StringBuilder uids = new StringBuilder(); + while (cursor.next()) { + int user_id = cursor.intValue(0); + TLRPC.TL_contact contact = new TLRPC.TL_contact(); + contact.user_id = user_id; + contact.mutual = cursor.intValue(1) == 1; if (uids.length() != 0) { - getUsersInternal(uids.toString(), users); + uids.append(","); } - } catch (Exception e) { - contacts.clear(); - users.clear(); - FileLog.e(e); + contacts.add(contact); + uids.append(contact.user_id); } - ContactsController.getInstance(currentAccount).processLoadedContacts(contacts, users, 1); + cursor.dispose(); + + if (uids.length() != 0) { + getUsersInternal(uids.toString(), users); + } + } catch (Exception e) { + contacts.clear(); + users.clear(); + FileLog.e(e); } + ContactsController.getInstance(currentAccount).processLoadedContacts(contacts, users, 1); }); } public void getUnsentMessages(final int count) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SparseArray messageHashMap = new SparseArray<>(); - ArrayList messages = new ArrayList<>(); - ArrayList users = new ArrayList<>(); - ArrayList chats = new ArrayList<>(); - ArrayList encryptedChats = new ArrayList<>(); + storageQueue.postRunnable(() -> { + try { + SparseArray messageHashMap = new SparseArray<>(); + ArrayList messages = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + ArrayList chats = new ArrayList<>(); + ArrayList encryptedChats = new ArrayList<>(); - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList broadcastIds = new ArrayList<>(); - ArrayList encryptedChatIds = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE (m.mid < 0 AND m.send_state = 1) OR (m.mid > 0 AND m.send_state = 3) ORDER BY m.mid DESC LIMIT " + count); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.send_state = cursor.intValue(2); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (messageHashMap.indexOfKey(message.id) < 0) { - MessageObject.setUnreadFlags(message, cursor.intValue(0)); - message.id = cursor.intValue(3); - message.date = cursor.intValue(4); - if (!cursor.isNull(5)) { - message.random_id = cursor.longValue(5); - } - message.dialog_id = cursor.longValue(6); - message.seq_in = cursor.intValue(7); - message.seq_out = cursor.intValue(8); - message.ttl = cursor.intValue(9); - messages.add(message); - messageHashMap.put(message.id, message); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList broadcastIds = new ArrayList<>(); + ArrayList encryptedChatIds = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE (m.mid < 0 AND m.send_state = 1) OR (m.mid > 0 AND m.send_state = 3) ORDER BY m.mid DESC LIMIT " + count); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(2); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (messageHashMap.indexOfKey(message.id) < 0) { + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + message.date = cursor.intValue(4); + if (!cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + message.dialog_id = cursor.longValue(6); + message.seq_in = cursor.intValue(7); + message.seq_out = cursor.intValue(8); + message.ttl = cursor.intValue(9); + messages.add(message); + messageHashMap.put(message.id, message); - int lower_id = (int) message.dialog_id; - int high_id = (int) (message.dialog_id >> 32); + int lower_id = (int) message.dialog_id; + int high_id = (int) (message.dialog_id >> 32); - if (lower_id != 0) { - if (high_id == 1) { - if (!broadcastIds.contains(lower_id)) { - broadcastIds.add(lower_id); - } - } else { - if (lower_id < 0) { - if (!chatsToLoad.contains(-lower_id)) { - chatsToLoad.add(-lower_id); - } - } else { - if (!usersToLoad.contains(lower_id)) { - usersToLoad.add(lower_id); - } - } + if (lower_id != 0) { + if (high_id == 1) { + if (!broadcastIds.contains(lower_id)) { + broadcastIds.add(lower_id); } } else { - if (!encryptedChatIds.contains(high_id)) { - encryptedChatIds.add(high_id); + if (lower_id < 0) { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } else { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } } } - - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - - if (message.send_state != 3 && (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0)) { - message.send_state = 0; - } - if (lower_id == 0 && !cursor.isNull(5)) { - message.random_id = cursor.longValue(5); + } else { + if (!encryptedChatIds.contains(high_id)) { + encryptedChatIds.add(high_id); } } - } - } - cursor.dispose(); + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - if (!encryptedChatIds.isEmpty()) { - getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); - } - - if (!usersToLoad.isEmpty()) { - getUsersInternal(TextUtils.join(",", usersToLoad), users); - } - - if (!chatsToLoad.isEmpty() || !broadcastIds.isEmpty()) { - StringBuilder stringToLoad = new StringBuilder(); - for (int a = 0; a < chatsToLoad.size(); a++) { - Integer cid = chatsToLoad.get(a); - if (stringToLoad.length() != 0) { - stringToLoad.append(","); + if (message.send_state != 3 && (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0)) { + message.send_state = 0; } - stringToLoad.append(cid); - } - for (int a = 0; a < broadcastIds.size(); a++) { - Integer cid = broadcastIds.get(a); - if (stringToLoad.length() != 0) { - stringToLoad.append(","); + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); } - stringToLoad.append(-cid); } - getChatsInternal(stringToLoad.toString(), chats); } - - SendMessagesHelper.getInstance(currentAccount).processUnsentMessages(messages, users, chats, encryptedChats); - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + + + if (!encryptedChatIds.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); + } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + + if (!chatsToLoad.isEmpty() || !broadcastIds.isEmpty()) { + StringBuilder stringToLoad = new StringBuilder(); + for (int a = 0; a < chatsToLoad.size(); a++) { + Integer cid = chatsToLoad.get(a); + if (stringToLoad.length() != 0) { + stringToLoad.append(","); + } + stringToLoad.append(cid); + } + for (int a = 0; a < broadcastIds.size(); a++) { + Integer cid = broadcastIds.get(a); + if (stringToLoad.length() != 0) { + stringToLoad.append(","); + } + stringToLoad.append(-cid); + } + getChatsInternal(stringToLoad.toString(), chats); + } + + SendMessagesHelper.getInstance(currentAccount).processUnsentMessages(messages, users, chats, encryptedChats); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3486,24 +3212,21 @@ public class MessagesStorage { public boolean checkMessageByRandomId(final long random_id) { final boolean[] result = new boolean[1]; final CountDownLatch countDownLatch = new CountDownLatch(1); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLiteCursor cursor = null; - try { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT random_id FROM randoms WHERE random_id = %d", random_id)); - if (cursor.next()) { - result[0] = true; - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT random_id FROM randoms WHERE random_id = %d", random_id)); + if (cursor.next()) { + result[0] = true; + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); } - countDownLatch.countDown(); } + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -3516,24 +3239,21 @@ public class MessagesStorage { public boolean checkMessageId(final long dialog_id, final int mid) { final boolean[] result = new boolean[1]; final CountDownLatch countDownLatch = new CountDownLatch(1); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLiteCursor cursor = null; - try { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d AND mid = %d", dialog_id, mid)); - if (cursor.next()) { - result[0] = true; - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d AND mid = %d", dialog_id, mid)); + if (cursor.next()) { + result[0] = true; + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); } - countDownLatch.countDown(); } + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -3544,295 +3264,301 @@ public class MessagesStorage { } public void getUnreadMention(final long dialog_id, final IntCallback callback) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - final int result; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT MIN(mid) FROM messages WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", dialog_id)); - if (cursor.next()) { - result = cursor.intValue(0); - } else { - result = 0; - } - cursor.dispose(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - callback.run(result); - } - }); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + final int result; + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT MIN(mid) FROM messages WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", dialog_id)); + if (cursor.next()) { + result = cursor.intValue(0); + } else { + result = 0; } + cursor.dispose(); + AndroidUtilities.runOnUIThread(() -> callback.run(result)); + } catch (Exception e) { + FileLog.e(e); } }); } public void getMessages(final long dialog_id, final int count, final int max_id, final int offset_date, final int minDate, final int classGuid, final int load_type, final boolean isChannel, final int loadIndex) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages(); - int count_unread = 0; - int mentions_unread = 0; - int count_query = count; - int offset_query = 0; - int min_unread_id = 0; - int last_message_id = 0; - boolean queryFromServer = false; - int max_unread_date = 0; - long messageMaxId = max_id; - int max_id_query = max_id; - boolean unreadCountIsLocal = false; - int max_id_override = max_id; - int channelId = 0; - if (isChannel) { - channelId = -(int) dialog_id; - } - if (messageMaxId != 0 && channelId != 0) { - messageMaxId |= ((long) channelId) << 32; - } - boolean isEnd = false; - int num = dialog_id == 777000 ? 10 : 1; - try { - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList replyMessages = new ArrayList<>(); - SparseArray> replyMessageOwners = new SparseArray<>(); - LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); + storageQueue.postRunnable(() -> { + TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages(); + int count_unread = 0; + int mentions_unread = 0; + int count_query = count; + int offset_query = 0; + int min_unread_id = 0; + int last_message_id = 0; + boolean queryFromServer = false; + int max_unread_date = 0; + long messageMaxId = max_id; + int max_id_query = max_id; + boolean unreadCountIsLocal = false; + int max_id_override = max_id; + int channelId = 0; + if (isChannel) { + channelId = -(int) dialog_id; + } + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + boolean isEnd = false; + int num = dialog_id == 777000 ? 10 : 1; + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList replyMessages = new ArrayList<>(); + SparseArray> replyMessageOwners = new SparseArray<>(); + LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); - SQLiteCursor cursor; - int lower_id = (int) dialog_id; - if (lower_id != 0) { - if (load_type == 3 && minDate == 0) { + SQLiteCursor cursor; + int lower_id = (int) dialog_id; + if (lower_id != 0) { + if (load_type == 3 && minDate == 0) { + cursor = database.queryFinalized("SELECT inbox_max, unread_count, date, unread_count_i FROM dialogs WHERE did = " + dialog_id); + if (cursor.next()) { + min_unread_id = cursor.intValue(0) + 1; + count_unread = cursor.intValue(1); + max_unread_date = cursor.intValue(2); + mentions_unread = cursor.intValue(3); + } + cursor.dispose(); + } else if (load_type != 1 && load_type != 3 && load_type != 4 && minDate == 0) { + if (load_type == 2) { cursor = database.queryFinalized("SELECT inbox_max, unread_count, date, unread_count_i FROM dialogs WHERE did = " + dialog_id); if (cursor.next()) { - min_unread_id = cursor.intValue(0) + 1; + messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); count_unread = cursor.intValue(1); max_unread_date = cursor.intValue(2); mentions_unread = cursor.intValue(3); + queryFromServer = true; + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } } cursor.dispose(); - } else if (load_type != 1 && load_type != 3 && load_type != 4 && minDate == 0) { - if (load_type == 2) { - cursor = database.queryFinalized("SELECT inbox_max, unread_count, date, unread_count_i FROM dialogs WHERE did = " + dialog_id); + if (!queryFromServer) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id)); if (cursor.next()) { - messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); - count_unread = cursor.intValue(1); - max_unread_date = cursor.intValue(2); - mentions_unread = cursor.intValue(3); - queryFromServer = true; - if (messageMaxId != 0 && channelId != 0) { - messageMaxId |= ((long) channelId) << 32; - } + min_unread_id = cursor.intValue(0); + max_unread_date = cursor.intValue(1); } cursor.dispose(); - if (!queryFromServer) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id)); + if (min_unread_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid >= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); if (cursor.next()) { - min_unread_id = cursor.intValue(0); - max_unread_date = cursor.intValue(1); + count_unread = cursor.intValue(0); } cursor.dispose(); - if (min_unread_id != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid >= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); - if (cursor.next()) { - count_unread = cursor.intValue(0); - } - cursor.dispose(); - } - } else if (max_id_query == 0) { - int existingUnreadCount = 0; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid > 0 AND out = 0 AND read_state IN(0,2)", dialog_id)); - if (cursor.next()) { - existingUnreadCount = cursor.intValue(0); - } - cursor.dispose(); - if (existingUnreadCount == count_unread) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id)); - if (cursor.next()) { - messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); - if (messageMaxId != 0 && channelId != 0) { - messageMaxId |= ((long) channelId) << 32; - } - } - cursor.dispose(); - } - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query)); - boolean containMessage = !cursor.next(); - cursor.dispose(); - - if (containMessage) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > %d", dialog_id, max_id_query)); - if (cursor.next()) { - messageMaxId = max_id_query = cursor.intValue(0); - if (messageMaxId != 0 && channelId != 0) { - messageMaxId |= ((long) channelId) << 32; - } - } - cursor.dispose(); - } } - } - - if (count_query > count_unread || count_unread < num) { - count_query = Math.max(count_query, count_unread + 10); - if (count_unread < num) { - count_unread = 0; - min_unread_id = 0; - messageMaxId = 0; - last_message_id = 0; - queryFromServer = false; + } else if (max_id_query == 0) { + int existingUnreadCount = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid > 0 AND out = 0 AND read_state IN(0,2)", dialog_id)); + if (cursor.next()) { + existingUnreadCount = cursor.intValue(0); + } + cursor.dispose(); + if (existingUnreadCount == count_unread) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id)); + if (cursor.next()) { + messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + } + cursor.dispose(); } } else { - offset_query = count_unread - count_query; - count_query += 10; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query)); + boolean containMessage = !cursor.next(); + cursor.dispose(); + + if (containMessage) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > %d", dialog_id, max_id_query)); + if (cursor.next()) { + messageMaxId = max_id_query = cursor.intValue(0); + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + } } } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start IN (0, 1)", dialog_id)); - if (cursor.next()) { - isEnd = cursor.intValue(0) == 1; - cursor.dispose(); + if (count_query > count_unread || count_unread < num) { + count_query = Math.max(count_query, count_unread + 10); + if (count_unread < num) { + count_unread = 0; + min_unread_id = 0; + messageMaxId = 0; + last_message_id = 0; + queryFromServer = false; + } } else { - cursor.dispose(); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); - if (cursor.next()) { - int mid = cursor.intValue(0); - if (mid != 0) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); - state.requery(); - state.bindLong(1, dialog_id); - state.bindInteger(2, 0); - state.bindInteger(3, mid); - state.step(); - state.dispose(); - } - } - cursor.dispose(); + offset_query = count_unread - count_query; + count_query += 10; } + } - if (load_type == 3 || load_type == 4 || queryFromServer && load_type == 2) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start IN (0, 1)", dialog_id)); + if (cursor.next()) { + isEnd = cursor.intValue(0) == 1; + cursor.dispose(); + } else { + cursor.dispose(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + int mid = cursor.intValue(0); + if (mid != 0) { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, 0); + state.bindInteger(3, mid); + state.step(); + state.dispose(); + } + } + cursor.dispose(); + } + + if (load_type == 3 || load_type == 4 || queryFromServer && load_type == 2) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + if (load_type == 4 && offset_date != 0) { + int startMid; + int endMid; + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND date <= %d AND mid > 0", dialog_id, offset_date)); if (cursor.next()) { - last_message_id = cursor.intValue(0); + startMid = cursor.intValue(0); + } else { + startMid = -1; } cursor.dispose(); - - if (load_type == 4 && offset_date != 0) { - int startMid; - int endMid; - - cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND date <= %d AND mid > 0", dialog_id, offset_date)); - if (cursor.next()) { - startMid = cursor.intValue(0); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND date >= %d AND mid > 0", dialog_id, offset_date)); + if (cursor.next()) { + endMid = cursor.intValue(0); + } else { + endMid = -1; + } + cursor.dispose(); + if (startMid != -1 && endMid != -1) { + if (startMid == endMid) { + max_id_query = startMid; } else { - startMid = -1; - } - cursor.dispose(); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND date >= %d AND mid > 0", dialog_id, offset_date)); - if (cursor.next()) { - endMid = cursor.intValue(0); - } else { - endMid = -1; - } - cursor.dispose(); - if (startMid != -1 && endMid != -1) { - if (startMid == endMid) { - max_id_query = startMid; - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, startMid, startMid)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, startMid, startMid)); + if (cursor.next()) { + startMid = -1; + } + cursor.dispose(); + if (startMid != -1) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, endMid, endMid)); if (cursor.next()) { - startMid = -1; + endMid = -1; } cursor.dispose(); - if (startMid != -1) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, endMid, endMid)); - if (cursor.next()) { - endMid = -1; - } - cursor.dispose(); - if (endMid != -1) { - max_id_override = endMid; - messageMaxId = max_id_query = endMid; - if (messageMaxId != 0 && channelId != 0) { - messageMaxId |= ((long) channelId) << 32; - } + if (endMid != -1) { + max_id_override = endMid; + messageMaxId = max_id_query = endMid; + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; } } } } } + } - boolean containMessage = max_id_query != 0; - if (containMessage) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query)); - if (cursor.next()) { - containMessage = false; - } - cursor.dispose(); + boolean containMessage = max_id_query != 0; + if (containMessage) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query)); + if (cursor.next()) { + containMessage = false; } + cursor.dispose(); + } - if (containMessage) { - long holeMessageMaxId = 0; - long holeMessageMinId = 1; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start >= %d ORDER BY start ASC LIMIT 1", dialog_id, max_id_query)); - if (cursor.next()) { - holeMessageMaxId = cursor.intValue(0); + if (containMessage) { + long holeMessageMaxId = 0; + long holeMessageMinId = 1; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start >= %d ORDER BY start ASC LIMIT 1", dialog_id, max_id_query)); + if (cursor.next()) { + holeMessageMaxId = cursor.intValue(0); + if (channelId != 0) { + holeMessageMaxId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id_query)); + if (cursor.next()) { + holeMessageMinId = cursor.intValue(0); + if (channelId != 0) { + holeMessageMinId |= ((long) channelId) << 32; + } + } + /*if (holeMessageMaxId == holeMessageMinId) { + holeMessageMaxId = 0; + holeMessageMinId = 1; + }*/ + cursor.dispose(); + if (holeMessageMaxId != 0 || holeMessageMinId != 1) { + if (holeMessageMaxId == 0) { + holeMessageMaxId = 1000000000; if (channelId != 0) { holeMessageMaxId |= ((long) channelId) << 32; } } - cursor.dispose(); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id_query)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d AND (m.mid <= %d OR m.mid < 0) ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, holeMessageMinId, count_query / 2, dialog_id, messageMaxId, holeMessageMaxId, count_query / 2)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); + } + } else { + if (load_type == 2) { + int existingUnreadCount = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid != 0 AND out = 0 AND read_state IN(0,2)", dialog_id)); if (cursor.next()) { - holeMessageMinId = cursor.intValue(0); - if (channelId != 0) { - holeMessageMinId |= ((long) channelId) << 32; - } + existingUnreadCount = cursor.intValue(0); } - /*if (holeMessageMaxId == holeMessageMinId) { - holeMessageMaxId = 0; - holeMessageMinId = 1; - }*/ cursor.dispose(); - if (holeMessageMaxId != 0 || holeMessageMinId != 1) { - if (holeMessageMaxId == 0) { - holeMessageMaxId = 1000000000; - if (channelId != 0) { - holeMessageMaxId |= ((long) channelId) << 32; - } - } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + - "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d AND (m.mid <= %d OR m.mid < 0) ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, holeMessageMinId, count_query / 2, dialog_id, messageMaxId, holeMessageMaxId, count_query / 2)); - } else { + if (existingUnreadCount == count_unread) { + unreadCountIsLocal = true; cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); - } - } else { - if (load_type == 2) { - int existingUnreadCount = 0; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid != 0 AND out = 0 AND read_state IN(0,2)", dialog_id)); - if (cursor.next()) { - existingUnreadCount = cursor.intValue(0); - } - cursor.dispose(); - if (existingUnreadCount == count_unread) { - unreadCountIsLocal = true; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + - "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); - } else { - cursor = null; - } } else { cursor = null; } + } else { + cursor = null; } - } else if (load_type == 1) { + } + } else if (load_type == 1) { + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start >= %d AND start != 1 AND end != 1 ORDER BY start ASC LIMIT 1", dialog_id, max_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d AND m.mid <= %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); + } + } else if (minDate != 0) { + if (messageMaxId != 0) { long holeMessageId = 0; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start >= %d AND start != 1 AND end != 1 ORDER BY start ASC LIMIT 1", dialog_id, max_id)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id)); if (cursor.next()) { holeMessageId = cursor.intValue(0); if (channelId != 0) { @@ -3841,71 +3567,95 @@ public class MessagesStorage { } cursor.dispose(); if (holeMessageId != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d AND m.mid <= %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); - } - } else if (minDate != 0) { - if (messageMaxId != 0) { - long holeMessageId = 0; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id)); - if (cursor.next()) { - holeMessageId = cursor.intValue(0); - if (channelId != 0) { - holeMessageId |= ((long) channelId) << 32; - } - } - cursor.dispose(); - if (holeMessageId != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); - } - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); } } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + } + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(end) FROM messages_holes WHERE uid = %d", dialog_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, holeMessageId, offset_query, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query)); + } + } + } else { + isEnd = true; + + if (load_type == 3 && minDate == 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); + if (cursor.next()) { + min_unread_id = cursor.intValue(0); + } + cursor.dispose(); + + int min_unread_id2 = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id)); + if (cursor.next()) { + min_unread_id2 = cursor.intValue(0); + max_unread_date = cursor.intValue(1); + } + cursor.dispose(); + if (min_unread_id2 != 0) { + min_unread_id = min_unread_id2; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id2)); + if (cursor.next()) { + count_unread = cursor.intValue(0); + } + cursor.dispose(); + } + } + + if (load_type == 3 || load_type == 4) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.mid DESC LIMIT %d) UNION " + + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); + } else if (load_type == 1) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query)); + } else if (minDate != 0) { + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", dialog_id, max_id, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + } + } else { + if (load_type == 2) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); if (cursor.next()) { last_message_id = cursor.intValue(0); } cursor.dispose(); - long holeMessageId = 0; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(end) FROM messages_holes WHERE uid = %d", dialog_id)); - if (cursor.next()) { - holeMessageId = cursor.intValue(0); - if (channelId != 0) { - holeMessageId |= ((long) channelId) << 32; - } - } - cursor.dispose(); - if (holeMessageId != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, holeMessageId, offset_query, count_query)); - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query)); - } - } - } else { - isEnd = true; - - if (load_type == 3 && minDate == 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); - if (cursor.next()) { - min_unread_id = cursor.intValue(0); - } - cursor.dispose(); - - int min_unread_id2 = 0; cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id)); if (cursor.next()) { - min_unread_id2 = cursor.intValue(0); + min_unread_id = cursor.intValue(0); max_unread_date = cursor.intValue(1); } cursor.dispose(); - if (min_unread_id2 != 0) { - min_unread_id = min_unread_id2; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id2)); + if (min_unread_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); if (cursor.next()) { count_unread = cursor.intValue(0); } @@ -3913,291 +3663,244 @@ public class MessagesStorage { } } - if (load_type == 3 || load_type == 4) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); - if (cursor.next()) { - last_message_id = cursor.intValue(0); - } - cursor.dispose(); - - cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.mid DESC LIMIT %d) UNION " + - "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); - } else if (load_type == 1) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query)); - } else if (minDate != 0) { - if (max_id != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", dialog_id, max_id, count_query)); - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + if (count_query > count_unread || count_unread < num) { + count_query = Math.max(count_query, count_unread + 10); + if (count_unread < num) { + count_unread = 0; + min_unread_id = 0; + last_message_id = 0; } } else { - if (load_type == 2) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); - if (cursor.next()) { - last_message_id = cursor.intValue(0); - } - cursor.dispose(); + offset_query = count_unread - count_query; + count_query += 10; + } + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query)); + } + } + int minId = Integer.MAX_VALUE; + int maxId = Integer.MIN_VALUE; + if (cursor != null) { + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.send_state = cursor.intValue(2); + if (message.id > 0 && message.send_state != 0 && message.send_state != 3) { + message.send_state = 0; + } + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + if (message.id > 0) { + minId = Math.min(message.id, minId); + maxId = Math.max(message.id, maxId); + } + message.date = cursor.intValue(4); + message.dialog_id = dialog_id; + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + message.views = cursor.intValue(7); + } + if (lower_id != 0 && message.ttl == 0) { + message.ttl = cursor.intValue(8); + } + if (cursor.intValue(9) != 0) { + message.mentioned = true; + } + res.messages.add(message); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id)); - if (cursor.next()) { - min_unread_id = cursor.intValue(0); - max_unread_date = cursor.intValue(1); - } - cursor.dispose(); - if (min_unread_id != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); - if (cursor.next()) { - count_unread = cursor.intValue(0); + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) { + if (!cursor.isNull(6)) { + data = cursor.byteBufferValue(6); + if (data != null) { + message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message.replyMessage != null) { + if (MessageObject.isMegagroup(message)) { + message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); + } + } + } + if (message.replyMessage == null) { + if (message.reply_to_msg_id != 0) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + ArrayList messages = replyMessageOwners.get(message.reply_to_msg_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageOwners.put(message.reply_to_msg_id, messages); + } + messages.add(message); + } else { + if (!replyMessages.contains(message.reply_to_random_id)) { + replyMessages.add(message.reply_to_random_id); + } + ArrayList messages = replyMessageRandomOwners.get(message.reply_to_random_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageRandomOwners.put(message.reply_to_random_id, messages); + } + messages.add(message); } - cursor.dispose(); } } - - if (count_query > count_unread || count_unread < num) { - count_query = Math.max(count_query, count_unread + 10); - if (count_unread < num) { - count_unread = 0; - min_unread_id = 0; - last_message_id = 0; - } - } else { - offset_query = count_unread - count_query; - count_query += 10; + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + if (MessageObject.isSecretPhotoOrVideo(message)) { + try { + SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id)); + if (cursor2.next()) { + message.destroyTime = cursor2.intValue(0); + } + cursor2.dispose(); + } catch (Exception e) { + FileLog.e(e); + } } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl, m.mention FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query)); } } - int minId = Integer.MAX_VALUE; - int maxId = Integer.MIN_VALUE; - if (cursor != null) { - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.send_state = cursor.intValue(2); - if (message.id > 0 && message.send_state != 0 && message.send_state != 3) { - message.send_state = 0; - } - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - MessageObject.setUnreadFlags(message, cursor.intValue(0)); - message.id = cursor.intValue(3); - if (message.id > 0) { - minId = Math.min(message.id, minId); - maxId = Math.max(message.id, maxId); - } - message.date = cursor.intValue(4); - message.dialog_id = dialog_id; - if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { - message.views = cursor.intValue(7); - } - if (lower_id != 0 && message.ttl == 0) { - message.ttl = cursor.intValue(8); - } - if (cursor.intValue(9) != 0) { - message.mentioned = true; - } - res.messages.add(message); + cursor.dispose(); + } - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - - if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) { - if (!cursor.isNull(6)) { - data = cursor.byteBufferValue(6); - if (data != null) { - message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message.replyMessage != null) { - if (MessageObject.isMegagroup(message)) { - message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); - } - } - } - if (message.replyMessage == null) { - if (message.reply_to_msg_id != 0) { - long messageId = message.reply_to_msg_id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; - } - if (!replyMessages.contains(messageId)) { - replyMessages.add(messageId); - } - ArrayList messages = replyMessageOwners.get(message.reply_to_msg_id); - if (messages == null) { - messages = new ArrayList<>(); - replyMessageOwners.put(message.reply_to_msg_id, messages); - } - messages.add(message); - } else { - if (!replyMessages.contains(message.reply_to_random_id)) { - replyMessages.add(message.reply_to_random_id); - } - ArrayList messages = replyMessageRandomOwners.get(message.reply_to_random_id); - if (messages == null) { - messages = new ArrayList<>(); - replyMessageRandomOwners.put(message.reply_to_random_id, messages); - } - messages.add(message); - } - } - } - if (lower_id == 0 && !cursor.isNull(5)) { - message.random_id = cursor.longValue(5); - } - if (MessageObject.isSecretPhotoOrVideo(message)) { - try { - SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id)); - if (cursor2.next()) { - message.destroyTime = cursor2.intValue(0); - } - cursor2.dispose(); - } catch (Exception e) { - FileLog.e(e); - } - } - } + Collections.sort(res.messages, (lhs, rhs) -> { + if (lhs.id > 0 && rhs.id > 0) { + if (lhs.id > rhs.id) { + return -1; + } else if (lhs.id < rhs.id) { + return 1; + } + } else if (lhs.id < 0 && rhs.id < 0) { + if (lhs.id < rhs.id) { + return -1; + } else if (lhs.id > rhs.id) { + return 1; + } + } else { + if (lhs.date > rhs.date) { + return -1; + } else if (lhs.date < rhs.date) { + return 1; } - cursor.dispose(); } + return 0; + }); - Collections.sort(res.messages, new Comparator() { - @Override - public int compare(TLRPC.Message lhs, TLRPC.Message rhs) { - if (lhs.id > 0 && rhs.id > 0) { - if (lhs.id > rhs.id) { - return -1; - } else if (lhs.id < rhs.id) { - return 1; - } - } else if (lhs.id < 0 && rhs.id < 0) { - if (lhs.id < rhs.id) { - return -1; - } else if (lhs.id > rhs.id) { - return 1; - } - } else { - if (lhs.date > rhs.date) { - return -1; - } else if (lhs.date < rhs.date) { - return 1; - } - } - return 0; - } - }); - - if (lower_id != 0) { - if ((load_type == 3 || load_type == 4 || load_type == 2 && queryFromServer && !unreadCountIsLocal) && !res.messages.isEmpty()) { - if (!(minId <= max_id_query && maxId >= max_id_query)) { - replyMessages.clear(); - usersToLoad.clear(); - chatsToLoad.clear(); - res.messages.clear(); - } - } - if ((load_type == 4 || load_type == 3) && res.messages.size() == 1) { + if (lower_id != 0) { + if ((load_type == 3 || load_type == 4 || load_type == 2 && queryFromServer && !unreadCountIsLocal) && !res.messages.isEmpty()) { + if (!(minId <= max_id_query && maxId >= max_id_query)) { + replyMessages.clear(); + usersToLoad.clear(); + chatsToLoad.clear(); res.messages.clear(); } } - if (!replyMessages.isEmpty()) { - if (replyMessageOwners.size() > 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); - } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); - } - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.dialog_id = dialog_id; + if ((load_type == 4 || load_type == 3) && res.messages.size() == 1) { + res.messages.clear(); + } + } + if (!replyMessages.isEmpty()) { + if (replyMessageOwners.size() > 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); + } + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialog_id; - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - if (replyMessageOwners.size() > 0) { - ArrayList arrayList = replyMessageOwners.get(message.id); - if (arrayList != null) { - for (int a = 0; a < arrayList.size(); a++) { - TLRPC.Message object = arrayList.get(a); - object.replyMessage = message; - if (MessageObject.isMegagroup(object)) { - object.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } - } - } else { - long value = cursor.longValue(3); - ArrayList arrayList = replyMessageRandomOwners.get(value); - replyMessageRandomOwners.remove(value); - if (arrayList != null) { - for (int a = 0; a < arrayList.size(); a++) { - TLRPC.Message object = arrayList.get(a); - object.replyMessage = message; - object.reply_to_msg_id = message.id; - if (MessageObject.isMegagroup(object)) { - object.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } + if (replyMessageOwners.size() > 0) { + ArrayList arrayList = replyMessageOwners.get(message.id); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message object = arrayList.get(a); + object.replyMessage = message; + if (MessageObject.isMegagroup(object)) { + object.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } } } - } - } - cursor.dispose(); - if (replyMessageRandomOwners.size() > 0) { - for (int b = 0; b < replyMessageRandomOwners.size(); b++) { - ArrayList arrayList = replyMessageRandomOwners.valueAt(b); - for (int a = 0; a < arrayList.size(); a++) { - arrayList.get(a).reply_to_random_id = 0; + } else { + long value = cursor.longValue(3); + ArrayList arrayList = replyMessageRandomOwners.get(value); + replyMessageRandomOwners.remove(value); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message object = arrayList.get(a); + object.replyMessage = message; + object.reply_to_msg_id = message.id; + if (MessageObject.isMegagroup(object)) { + object.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } } } } } - - if (mentions_unread != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM messages WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", dialog_id)); - if (cursor.next()) { - if (mentions_unread != cursor.intValue(0)) { - mentions_unread *= -1; + cursor.dispose(); + if (replyMessageRandomOwners.size() > 0) { + for (int b = 0; b < replyMessageRandomOwners.size(); b++) { + ArrayList arrayList = replyMessageRandomOwners.valueAt(b); + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).reply_to_random_id = 0; } - } else { + } + } + } + + if (mentions_unread != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM messages WHERE uid = %d AND mention = 1 AND read_state IN(0, 1)", dialog_id)); + if (cursor.next()) { + if (mentions_unread != cursor.intValue(0)) { mentions_unread *= -1; } - cursor.dispose(); + } else { + mentions_unread *= -1; } - - if (!usersToLoad.isEmpty()) { - getUsersInternal(TextUtils.join(",", usersToLoad), res.users); - } - if (!chatsToLoad.isEmpty()) { - getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats); - } - } catch (Exception e) { - res.messages.clear(); - res.chats.clear(); - res.users.clear(); - FileLog.e(e); - } finally { - MessagesController.getInstance(currentAccount).processLoadedMessages(res, dialog_id, count_query, max_id_override, offset_date, true, classGuid, min_unread_id, last_message_id, count_unread, max_unread_date, load_type, isChannel, isEnd, loadIndex, queryFromServer, mentions_unread); + cursor.dispose(); } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), res.users); + } + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats); + } + } catch (Exception e) { + res.messages.clear(); + res.chats.clear(); + res.users.clear(); + FileLog.e(e); + } finally { + MessagesController.getInstance(currentAccount).processLoadedMessages(res, dialog_id, count_query, max_id_override, offset_date, true, classGuid, min_unread_id, last_message_id, count_unread, max_unread_date, load_type, isChannel, isEnd, loadIndex, queryFromServer, mentions_unread); } }); } public void clearSentMedia() { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -4208,32 +3911,29 @@ public class MessagesStorage { } final CountDownLatch countDownLatch = new CountDownLatch(1); final ArrayList result = new ArrayList<>(); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - String id = Utilities.MD5(path); - if (id != null) { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM sent_files_v2 WHERE uid = '%s' AND type = %d", id, type)); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLObject file = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - if (file instanceof TLRPC.TL_messageMediaDocument) { - result.add(((TLRPC.TL_messageMediaDocument) file).document); - } else if (file instanceof TLRPC.TL_messageMediaPhoto) { - result.add(((TLRPC.TL_messageMediaPhoto) file).photo); - } + storageQueue.postRunnable(() -> { + try { + String id = Utilities.MD5(path); + if (id != null) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM sent_files_v2 WHERE uid = '%s' AND type = %d", id, type)); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLObject file = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + if (file instanceof TLRPC.TL_messageMediaDocument) { + result.add(((TLRPC.TL_messageMediaDocument) file).document); + } else if (file instanceof TLRPC.TL_messageMediaPhoto) { + result.add(((TLRPC.TL_messageMediaPhoto) file).photo); } } - cursor.dispose(); } - } catch (Exception e) { - FileLog.e(e); - } finally { - countDownLatch.countDown(); + cursor.dispose(); } + } catch (Exception e) { + FileLog.e(e); + } finally { + countDownLatch.countDown(); } }); try { @@ -4248,42 +3948,39 @@ public class MessagesStorage { if (path == null || file == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLitePreparedStatement state = null; - try { - String id = Utilities.MD5(path); - if (id != null) { - TLRPC.MessageMedia messageMedia = null; - if (file instanceof TLRPC.Photo) { - messageMedia = new TLRPC.TL_messageMediaPhoto(); - messageMedia.photo = (TLRPC.Photo) file; - messageMedia.flags |= 1; - } else if (file instanceof TLRPC.Document) { - messageMedia = new TLRPC.TL_messageMediaDocument(); - messageMedia.document = (TLRPC.Document) file; - messageMedia.flags |= 1; - } - if (messageMedia == null) { - return; - } - state = database.executeFast("REPLACE INTO sent_files_v2 VALUES(?, ?, ?)"); - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(messageMedia.getObjectSize()); - messageMedia.serializeToStream(data); - state.bindString(1, id); - state.bindInteger(2, type); - state.bindByteBuffer(3, data); - state.step(); - data.reuse(); + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + String id = Utilities.MD5(path); + if (id != null) { + TLRPC.MessageMedia messageMedia = null; + if (file instanceof TLRPC.Photo) { + messageMedia = new TLRPC.TL_messageMediaPhoto(); + messageMedia.photo = (TLRPC.Photo) file; + messageMedia.flags |= 1; + } else if (file instanceof TLRPC.Document) { + messageMedia = new TLRPC.TL_messageMediaDocument(); + messageMedia.document = (TLRPC.Document) file; + messageMedia.flags |= 1; } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); + if (messageMedia == null) { + return; } + state = database.executeFast("REPLACE INTO sent_files_v2 VALUES(?, ?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(messageMedia.getObjectSize()); + messageMedia.serializeToStream(data); + state.bindString(1, id); + state.bindInteger(2, type); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); } } }); @@ -4293,29 +3990,26 @@ public class MessagesStorage { if (chat == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLitePreparedStatement state = null; - try { - state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ?, use_count = ?, in_seq_no = ?, mtproto_seq = ? WHERE uid = ?"); - state.bindInteger(1, chat.seq_in); - state.bindInteger(2, chat.seq_out); - state.bindInteger(3, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); - state.bindInteger(4, chat.in_seq_no); - state.bindInteger(5, chat.mtproto_seq); - state.bindInteger(6, chat.id); - state.step(); - if (cleanup) { - long did = ((long) chat.id) << 32; - database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN (SELECT m.mid FROM messages as m LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.uid = %d AND m.date = 0 AND m.mid < 0 AND s.seq_out <= %d)", did, chat.in_seq_no)).stepThis().dispose(); - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ?, use_count = ?, in_seq_no = ?, mtproto_seq = ? WHERE uid = ?"); + state.bindInteger(1, chat.seq_in); + state.bindInteger(2, chat.seq_out); + state.bindInteger(3, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindInteger(4, chat.in_seq_no); + state.bindInteger(5, chat.mtproto_seq); + state.bindInteger(6, chat.id); + state.step(); + if (cleanup) { + long did = ((long) chat.id) << 32; + database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN (SELECT m.mid FROM messages as m LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.uid = %d AND m.date = 0 AND m.mid < 0 AND s.seq_out <= %d)", did, chat.in_seq_no)).stepThis().dispose(); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); } } }); @@ -4325,21 +4019,18 @@ public class MessagesStorage { if (chat == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLitePreparedStatement state = null; - try { - state = database.executeFast("UPDATE enc_chats SET ttl = ? WHERE uid = ?"); - state.bindInteger(1, chat.ttl); - state.bindInteger(2, chat.id); - state.step(); - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET ttl = ? WHERE uid = ?"); + state.bindInteger(1, chat.ttl); + state.bindInteger(2, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); } } }); @@ -4349,21 +4040,18 @@ public class MessagesStorage { if (chat == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLitePreparedStatement state = null; - try { - state = database.executeFast("UPDATE enc_chats SET layer = ? WHERE uid = ?"); - state.bindInteger(1, chat.layer); - state.bindInteger(2, chat.id); - state.step(); - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET layer = ? WHERE uid = ?"); + state.bindInteger(1, chat.layer); + state.bindInteger(2, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); } } }); @@ -4373,64 +4061,61 @@ public class MessagesStorage { if (chat == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLitePreparedStatement state = null; - try { - if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { - chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); - } + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); + } - state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ?, use_count = ?, exchange_id = ?, key_date = ?, fprint = ?, fauthkey = ?, khash = ?, in_seq_no = ?, admin_id = ?, mtproto_seq = ? WHERE uid = ?"); - NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); - NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); - NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); - NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); - NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); - chat.serializeToStream(data); - state.bindByteBuffer(1, data); - if (chat.a_or_b != null) { - data2.writeBytes(chat.a_or_b); - } - if (chat.auth_key != null) { - data3.writeBytes(chat.auth_key); - } - if (chat.future_auth_key != null) { - data4.writeBytes(chat.future_auth_key); - } - if (chat.key_hash != null) { - data5.writeBytes(chat.key_hash); - } - state.bindByteBuffer(2, data2); - state.bindByteBuffer(3, data3); - state.bindInteger(4, chat.ttl); - state.bindInteger(5, chat.layer); - state.bindInteger(6, chat.seq_in); - state.bindInteger(7, chat.seq_out); - state.bindInteger(8, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); - state.bindLong(9, chat.exchange_id); - state.bindInteger(10, chat.key_create_date); - state.bindLong(11, chat.future_key_fingerprint); - state.bindByteBuffer(12, data4); - state.bindByteBuffer(13, data5); - state.bindInteger(14, chat.in_seq_no); - state.bindInteger(15, chat.admin_id); - state.bindInteger(16, chat.mtproto_seq); - state.bindInteger(17, chat.id); + state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ?, use_count = ?, exchange_id = ?, key_date = ?, fprint = ?, fauthkey = ?, khash = ?, in_seq_no = ?, admin_id = ?, mtproto_seq = ? WHERE uid = ?"); + NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); + NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); + NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); + NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); + chat.serializeToStream(data); + state.bindByteBuffer(1, data); + if (chat.a_or_b != null) { + data2.writeBytes(chat.a_or_b); + } + if (chat.auth_key != null) { + data3.writeBytes(chat.auth_key); + } + if (chat.future_auth_key != null) { + data4.writeBytes(chat.future_auth_key); + } + if (chat.key_hash != null) { + data5.writeBytes(chat.key_hash); + } + state.bindByteBuffer(2, data2); + state.bindByteBuffer(3, data3); + state.bindInteger(4, chat.ttl); + state.bindInteger(5, chat.layer); + state.bindInteger(6, chat.seq_in); + state.bindInteger(7, chat.seq_out); + state.bindInteger(8, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindLong(9, chat.exchange_id); + state.bindInteger(10, chat.key_create_date); + state.bindLong(11, chat.future_key_fingerprint); + state.bindByteBuffer(12, data4); + state.bindByteBuffer(13, data5); + state.bindInteger(14, chat.in_seq_no); + state.bindInteger(15, chat.admin_id); + state.bindInteger(16, chat.mtproto_seq); + state.bindInteger(17, chat.id); - state.step(); - data.reuse(); - data2.reuse(); - data3.reuse(); - data4.reuse(); - data5.reuse(); - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } + state.step(); + data.reuse(); + data2.reuse(); + data3.reuse(); + data4.reuse(); + data5.reuse(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); } } }); @@ -4439,18 +4124,15 @@ public class MessagesStorage { public boolean isDialogHasMessages(final long did) { final CountDownLatch countDownLatch = new CountDownLatch(1); final boolean result[] = new boolean[1]; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d LIMIT 1", did)); - result[0] = cursor.next(); - cursor.dispose(); - } catch (Exception e) { - FileLog.e(e); - } finally { - countDownLatch.countDown(); - } + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d LIMIT 1", did)); + result[0] = cursor.next(); + cursor.dispose(); + } catch (Exception e) { + FileLog.e(e); + } finally { + countDownLatch.countDown(); } }); try { @@ -4464,18 +4146,15 @@ public class MessagesStorage { public boolean hasAuthMessage(final int date) { final CountDownLatch countDownLatch = new CountDownLatch(1); final boolean result[] = new boolean[1]; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = 777000 AND date = %d AND mid < 0 LIMIT 1", date)); - result[0] = cursor.next(); - cursor.dispose(); - } catch (Exception e) { - FileLog.e(e); - } finally { - countDownLatch.countDown(); - } + storageQueue.postRunnable(() -> { + try { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = 777000 AND date = %d AND mid < 0 LIMIT 1", date)); + result[0] = cursor.next(); + cursor.dispose(); + } catch (Exception e) { + FileLog.e(e); + } finally { + countDownLatch.countDown(); } }); try { @@ -4490,26 +4169,23 @@ public class MessagesStorage { if (countDownLatch == null || result == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - ArrayList usersToLoad = new ArrayList<>(); - ArrayList encryptedChats = new ArrayList<>(); - getEncryptedChatsInternal("" + chat_id, encryptedChats, usersToLoad); - if (!encryptedChats.isEmpty() && !usersToLoad.isEmpty()) { - ArrayList users = new ArrayList<>(); - getUsersInternal(TextUtils.join(",", usersToLoad), users); - if (!users.isEmpty()) { - result.add(encryptedChats.get(0)); - result.add(users.get(0)); - } + storageQueue.postRunnable(() -> { + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList encryptedChats = new ArrayList<>(); + getEncryptedChatsInternal("" + chat_id, encryptedChats, usersToLoad); + if (!encryptedChats.isEmpty() && !usersToLoad.isEmpty()) { + ArrayList users = new ArrayList<>(); + getUsersInternal(TextUtils.join(",", usersToLoad), users); + if (!users.isEmpty()) { + result.add(encryptedChats.get(0)); + result.add(users.get(0)); } - } catch (Exception e) { - FileLog.e(e); - } finally { - countDownLatch.countDown(); } + } catch (Exception e) { + FileLog.e(e); + } finally { + countDownLatch.countDown(); } }); } @@ -4518,80 +4194,77 @@ public class MessagesStorage { if (chat == null) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { - chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); - } - SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); - NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); - NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); - NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); - NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); + storageQueue.postRunnable(() -> { + try { + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); + NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); + NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); + NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); - chat.serializeToStream(data); - state.bindInteger(1, chat.id); - state.bindInteger(2, user.id); - state.bindString(3, formatUserSearchName(user)); - state.bindByteBuffer(4, data); - if (chat.a_or_b != null) { - data2.writeBytes(chat.a_or_b); - } - if (chat.auth_key != null) { - data3.writeBytes(chat.auth_key); - } - if (chat.future_auth_key != null) { - data4.writeBytes(chat.future_auth_key); - } - if (chat.key_hash != null) { - data5.writeBytes(chat.key_hash); - } - state.bindByteBuffer(5, data2); - state.bindByteBuffer(6, data3); - state.bindInteger(7, chat.ttl); - state.bindInteger(8, chat.layer); - state.bindInteger(9, chat.seq_in); - state.bindInteger(10, chat.seq_out); - state.bindInteger(11, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); - state.bindLong(12, chat.exchange_id); - state.bindInteger(13, chat.key_create_date); - state.bindLong(14, chat.future_key_fingerprint); - state.bindByteBuffer(15, data4); - state.bindByteBuffer(16, data5); - state.bindInteger(17, chat.in_seq_no); - state.bindInteger(18, chat.admin_id); - state.bindInteger(19, chat.mtproto_seq); + chat.serializeToStream(data); + state.bindInteger(1, chat.id); + state.bindInteger(2, user.id); + state.bindString(3, formatUserSearchName(user)); + state.bindByteBuffer(4, data); + if (chat.a_or_b != null) { + data2.writeBytes(chat.a_or_b); + } + if (chat.auth_key != null) { + data3.writeBytes(chat.auth_key); + } + if (chat.future_auth_key != null) { + data4.writeBytes(chat.future_auth_key); + } + if (chat.key_hash != null) { + data5.writeBytes(chat.key_hash); + } + state.bindByteBuffer(5, data2); + state.bindByteBuffer(6, data3); + state.bindInteger(7, chat.ttl); + state.bindInteger(8, chat.layer); + state.bindInteger(9, chat.seq_in); + state.bindInteger(10, chat.seq_out); + state.bindInteger(11, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindLong(12, chat.exchange_id); + state.bindInteger(13, chat.key_create_date); + state.bindLong(14, chat.future_key_fingerprint); + state.bindByteBuffer(15, data4); + state.bindByteBuffer(16, data5); + state.bindInteger(17, chat.in_seq_no); + state.bindInteger(18, chat.admin_id); + state.bindInteger(19, chat.mtproto_seq); + state.step(); + state.dispose(); + data.reuse(); + data2.reuse(); + data3.reuse(); + data4.reuse(); + data5.reuse(); + if (dialog != null) { + state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state.bindLong(1, dialog.id); + state.bindInteger(2, dialog.last_message_date); + state.bindInteger(3, dialog.unread_count); + state.bindInteger(4, dialog.top_message); + state.bindInteger(5, dialog.read_inbox_max_id); + state.bindInteger(6, dialog.read_outbox_max_id); + state.bindInteger(7, 0); + state.bindInteger(8, dialog.unread_mentions_count); + state.bindInteger(9, dialog.pts); + state.bindInteger(10, 0); + state.bindInteger(11, dialog.pinnedNum); + state.bindInteger(12, dialog.flags); state.step(); state.dispose(); - data.reuse(); - data2.reuse(); - data3.reuse(); - data4.reuse(); - data5.reuse(); - if (dialog != null) { - state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - state.bindLong(1, dialog.id); - state.bindInteger(2, dialog.last_message_date); - state.bindInteger(3, dialog.unread_count); - state.bindInteger(4, dialog.top_message); - state.bindInteger(5, dialog.read_inbox_max_id); - state.bindInteger(6, dialog.read_outbox_max_id); - state.bindInteger(7, 0); - state.bindInteger(8, dialog.unread_mentions_count); - state.bindInteger(9, dialog.pts); - state.bindInteger(10, 0); - state.bindInteger(11, dialog.pinnedNum); - state.bindInteger(12, dialog.flags); - state.step(); - state.dispose(); - } - } catch (Exception e) { - FileLog.e(e); } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -4845,94 +4518,75 @@ public class MessagesStorage { return; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - putUsersAndChatsInternal(users, chats, withTransaction); - } - }); + storageQueue.postRunnable(() -> putUsersAndChatsInternal(users, chats, withTransaction)); } else { putUsersAndChatsInternal(users, chats, withTransaction); } } public void removeFromDownloadQueue(final long id, final int type, final boolean move) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (move) { - int minDate = -1; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(date) FROM download_queue WHERE type = %d", type)); - if (cursor.next()) { - minDate = cursor.intValue(0); - } - cursor.dispose(); - if (minDate != -1) { - database.executeFast(String.format(Locale.US, "UPDATE download_queue SET date = %d WHERE uid = %d AND type = %d", minDate - 1, id, type)).stepThis().dispose(); - } - } else { - database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE uid = %d AND type = %d", id, type)).stepThis().dispose(); + storageQueue.postRunnable(() -> { + try { + if (move) { + int minDate = -1; + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(date) FROM download_queue WHERE type = %d", type)); + if (cursor.next()) { + minDate = cursor.intValue(0); } - } catch (Exception e) { - FileLog.e(e); + cursor.dispose(); + if (minDate != -1) { + database.executeFast(String.format(Locale.US, "UPDATE download_queue SET date = %d WHERE uid = %d AND type = %d", minDate - 1, id, type)).stepThis().dispose(); + } + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE uid = %d AND type = %d", id, type)).stepThis().dispose(); } + } catch (Exception e) { + FileLog.e(e); } }); } public void clearDownloadQueue(final int type) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (type == 0) { - database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); - } else { - database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE type = %d", type)).stepThis().dispose(); - } - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + if (type == 0) { + database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE type = %d", type)).stepThis().dispose(); } + } catch (Exception e) { + FileLog.e(e); } }); } public void getDownloadQueue(final int type) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - final ArrayList objects = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, type, data FROM download_queue WHERE type = %d ORDER BY date DESC LIMIT 3", type)); - while (cursor.next()) { - DownloadObject downloadObject = new DownloadObject(); - downloadObject.type = cursor.intValue(1); - downloadObject.id = cursor.longValue(0); - NativeByteBuffer data = cursor.byteBufferValue(2); - if (data != null) { - TLRPC.MessageMedia messageMedia = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - if (messageMedia.document != null) { - downloadObject.object = messageMedia.document; - } else if (messageMedia.photo != null) { - downloadObject.object = FileLoader.getClosestPhotoSizeWithSize(messageMedia.photo.sizes, AndroidUtilities.getPhotoSize()); - } - downloadObject.secret = messageMedia.ttl_seconds != 0; + storageQueue.postRunnable(() -> { + try { + final ArrayList objects = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, type, data FROM download_queue WHERE type = %d ORDER BY date DESC LIMIT 3", type)); + while (cursor.next()) { + DownloadObject downloadObject = new DownloadObject(); + downloadObject.type = cursor.intValue(1); + downloadObject.id = cursor.longValue(0); + NativeByteBuffer data = cursor.byteBufferValue(2); + if (data != null) { + TLRPC.MessageMedia messageMedia = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + if (messageMedia.document != null) { + downloadObject.object = messageMedia.document; + } else if (messageMedia.photo != null) { + downloadObject.object = FileLoader.getClosestPhotoSizeWithSize(messageMedia.photo.sizes, AndroidUtilities.getPhotoSize()); } - objects.add(downloadObject); + downloadObject.secret = messageMedia.ttl_seconds != 0; } - cursor.dispose(); - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - DownloadController.getInstance(currentAccount).processDownloadObjects(type, objects); - } - }); - } catch (Exception e) { - FileLog.e(e); + objects.add(downloadObject); } + cursor.dispose(); + + AndroidUtilities.runOnUIThread(() -> DownloadController.getInstance(currentAccount).processDownloadObjects(type, objects)); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -4959,156 +4613,140 @@ public class MessagesStorage { if (isEmpty(webPages)) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - final ArrayList messages = new ArrayList<>(); - for (int a = 0; a < webPages.size(); a++) { - SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM webpage_pending WHERE id = " + webPages.keyAt(a)); - ArrayList mids = new ArrayList<>(); - while (cursor.next()) { - mids.add(cursor.longValue(0)); - } - cursor.dispose(); + storageQueue.postRunnable(() -> { + try { + final ArrayList messages = new ArrayList<>(); + for (int a = 0; a < webPages.size(); a++) { + SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM webpage_pending WHERE id = " + webPages.keyAt(a)); + ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + mids.add(cursor.longValue(0)); + } + cursor.dispose(); - if (mids.isEmpty()) { - continue; - } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, data FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); - while (cursor.next()) { - int mid = cursor.intValue(0); - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message.media instanceof TLRPC.TL_messageMediaWebPage) { - message.id = mid; - message.media.webpage = webPages.valueAt(a); - messages.add(message); - } + if (mids.isEmpty()) { + continue; + } + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, data FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); + while (cursor.next()) { + int mid = cursor.intValue(0); + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + message.id = mid; + message.media.webpage = webPages.valueAt(a); + messages.add(message); } } - cursor.dispose(); } - - //database.executeFast(String.format(Locale.US, "DELETE FROM webpage_pending WHERE id IN (%s)", ids)).stepThis().dispose(); - - if (messages.isEmpty()) { - return; - } - - database.beginTransaction(); - - SQLitePreparedStatement state = database.executeFast("UPDATE messages SET data = ? WHERE mid = ?"); - SQLitePreparedStatement state2 = database.executeFast("UPDATE media_v2 SET data = ? WHERE mid = ?"); - for (int a = 0; a < messages.size(); a++) { - TLRPC.Message message = messages.get(a); - NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); - message.serializeToStream(data); - - long messageId = message.id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; - } - - state.requery(); - state.bindByteBuffer(1, data); - state.bindLong(2, messageId); - state.step(); - - state2.requery(); - state2.bindByteBuffer(1, data); - state2.bindLong(2, messageId); - state2.step(); - - data.reuse(); - } - state.dispose(); - state2.dispose(); - - database.commitTransaction(); - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didReceivedWebpages, messages); - } - }); - } catch (Exception e) { - FileLog.e(e); + cursor.dispose(); } + + //database.executeFast(String.format(Locale.US, "DELETE FROM webpage_pending WHERE id IN (%s)", ids)).stepThis().dispose(); + + if (messages.isEmpty()) { + return; + } + + database.beginTransaction(); + + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET data = ? WHERE mid = ?"); + SQLitePreparedStatement state2 = database.executeFast("UPDATE media_v2 SET data = ? WHERE mid = ?"); + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + state.requery(); + state.bindByteBuffer(1, data); + state.bindLong(2, messageId); + state.step(); + + state2.requery(); + state2.bindByteBuffer(1, data); + state2.bindLong(2, messageId); + state2.step(); + + data.reuse(); + } + state.dispose(); + state2.dispose(); + + database.commitTransaction(); + + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didReceivedWebpages, messages)); + } catch (Exception e) { + FileLog.e(e); } }); } public void overwriteChannel(final int channel_id, final TLRPC.TL_updates_channelDifferenceTooLong difference, final int newDialogType) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - boolean checkInvite = false; - final long did = -channel_id; - int pinned = 0; + storageQueue.postRunnable(() -> { + try { + boolean checkInvite = false; + final long did = -channel_id; + int pinned = 0; - SQLiteCursor cursor = database.queryFinalized("SELECT pts, pinned FROM dialogs WHERE did = " + did); - if (!cursor.next()) { - if (newDialogType != 0) { - checkInvite = true; - } - } else { - pinned = cursor.intValue(1); + SQLiteCursor cursor = database.queryFinalized("SELECT pts, pinned FROM dialogs WHERE did = " + did); + if (!cursor.next()) { + if (newDialogType != 0) { + checkInvite = true; } - cursor.dispose(); - - - database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); - DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); - - TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); - dialogs.chats.addAll(difference.chats); - dialogs.users.addAll(difference.users); - dialogs.messages.addAll(difference.messages); - TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); - dialog.id = did; - dialog.flags = 1; - dialog.peer = new TLRPC.TL_peerChannel(); - dialog.peer.channel_id = channel_id; - dialog.top_message = difference.top_message; - dialog.read_inbox_max_id = difference.read_inbox_max_id; - dialog.read_outbox_max_id = difference.read_outbox_max_id; - dialog.unread_count = difference.unread_count; - dialog.unread_mentions_count = difference.unread_mentions_count; - dialog.notify_settings = null; - dialog.pinned = pinned != 0; - dialog.pinnedNum = pinned; - dialog.pts = difference.pts; - dialogs.dialogs.add(dialog); - putDialogsInternal(dialogs, 0); - - updateDialogsWithDeletedMessages(new ArrayList(), null, false, channel_id); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, true); - } - }); - if (checkInvite) { - if (newDialogType == 1) { - MessagesController.getInstance(currentAccount).checkChannelInviter(channel_id); - } else { - MessagesController.getInstance(currentAccount).generateJoinMessage(channel_id, false); - } - } - } catch (Exception e) { - FileLog.e(e); + } else { + pinned = cursor.intValue(1); } + cursor.dispose(); + + + database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + DataQuery.getInstance(currentAccount).clearBotKeyboard(did, null); + + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + dialogs.chats.addAll(difference.chats); + dialogs.users.addAll(difference.users); + dialogs.messages.addAll(difference.messages); + TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); + dialog.id = did; + dialog.flags = 1; + dialog.peer = new TLRPC.TL_peerChannel(); + dialog.peer.channel_id = channel_id; + dialog.top_message = difference.top_message; + dialog.read_inbox_max_id = difference.read_inbox_max_id; + dialog.read_outbox_max_id = difference.read_outbox_max_id; + dialog.unread_count = difference.unread_count; + dialog.unread_mentions_count = difference.unread_mentions_count; + dialog.notify_settings = null; + dialog.pinned = pinned != 0; + dialog.pinnedNum = pinned; + dialog.pts = difference.pts; + dialogs.dialogs.add(dialog); + putDialogsInternal(dialogs, 0); + + updateDialogsWithDeletedMessages(new ArrayList<>(), null, false, channel_id); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, true)); + if (checkInvite) { + if (newDialogType == 1) { + MessagesController.getInstance(currentAccount).checkChannelInviter(channel_id); + } else { + MessagesController.getInstance(currentAccount).generateJoinMessage(channel_id, false); + } + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -5117,33 +4755,30 @@ public class MessagesStorage { if (isEmpty(channelViews)) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("UPDATE messages SET media = max((SELECT media FROM messages WHERE mid = ?), ?) WHERE mid = ?"); - for (int a = 0; a < channelViews.size(); a++) { - int peer = channelViews.keyAt(a); - SparseIntArray messages = channelViews.get(peer); - for (int b = 0; b < messages.size(); b++) { - int views = messages.get(messages.keyAt(b)); - long messageId = messages.keyAt(b); - if (isChannel) { - messageId |= ((long) -peer) << 32; - } - state.requery(); - state.bindLong(1, messageId); - state.bindInteger(2, views); - state.bindLong(3, messageId); - state.step(); + storageQueue.postRunnable(() -> { + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET media = max((SELECT media FROM messages WHERE mid = ?), ?) WHERE mid = ?"); + for (int a = 0; a < channelViews.size(); a++) { + int peer = channelViews.keyAt(a); + SparseIntArray messages = channelViews.get(peer); + for (int b = 0; b < messages.size(); b++) { + int views = messages.get(messages.keyAt(b)); + long messageId = messages.keyAt(b); + if (isChannel) { + messageId |= ((long) -peer) << 32; } + state.requery(); + state.bindLong(1, messageId); + state.bindInteger(2, views); + state.bindLong(3, messageId); + state.step(); } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e(e); } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -5576,12 +5211,7 @@ public class MessagesStorage { if (downloadMediaMask != 0) { final int downloadMediaMaskFinal = downloadMediaMask; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - DownloadController.getInstance(currentAccount).newDownloadObjectsAvailable(downloadMediaMaskFinal); - } - }); + AndroidUtilities.runOnUIThread(() -> DownloadController.getInstance(currentAccount).newDownloadObjectsAvailable(downloadMediaMaskFinal)); } } catch (Exception e) { FileLog.e(e); @@ -5597,30 +5227,22 @@ public class MessagesStorage { return; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage); - } - }); + storageQueue.postRunnable(() -> putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage)); } else { putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage); } } public void markMessageAsSendError(final TLRPC.Message message) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - long messageId = message.id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; - } - database.executeFast("UPDATE messages SET send_state = 2 WHERE mid = " + messageId).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; } + database.executeFast("UPDATE messages SET send_state = 2 WHERE mid = " + messageId).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -5680,20 +5302,17 @@ public class MessagesStorage { }*/ public void setMessageSeq(final int mid, final int seq_in, final int seq_out) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_seq VALUES(?, ?, ?)"); - state.requery(); - state.bindInteger(1, mid); - state.bindInteger(2, seq_in); - state.bindInteger(3, seq_out); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } + storageQueue.postRunnable(() -> { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_seq VALUES(?, ?, ?)"); + state.requery(); + state.bindInteger(1, mid); + state.bindInteger(2, seq_in); + state.bindInteger(3, seq_out); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -5817,12 +5436,7 @@ public class MessagesStorage { public long[] updateMessageStateAndId(final long random_id, final Integer _oldId, final int newId, final int date, boolean useQueue, final int channelId) { if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - updateMessageStateAndIdInternal(random_id, _oldId, newId, date, channelId); - } - }); + storageQueue.postRunnable(() -> updateMessageStateAndIdInternal(random_id, _oldId, newId, date, channelId)); } else { return updateMessageStateAndIdInternal(random_id, _oldId, newId, date, channelId); } @@ -5902,12 +5516,7 @@ public class MessagesStorage { return; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - updateUsersInternal(users, onlyStatus, withTransaction); - } - }); + storageQueue.postRunnable(() -> updateUsersInternal(users, onlyStatus, withTransaction)); } else { updateUsersInternal(users, onlyStatus, withTransaction); } @@ -5950,41 +5559,33 @@ public class MessagesStorage { if (isEmpty(mids)) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - String midsStr = TextUtils.join(",", mids); - database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE mid IN (%s)", midsStr)).stepThis().dispose(); - if (date != 0) { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE mid IN (%s) AND ttl > 0", midsStr)); - ArrayList arrayList = null; - while (cursor.next()) { - if (arrayList == null) { - arrayList = new ArrayList<>(); - } - arrayList.add(cursor.intValue(0)); + storageQueue.postRunnable(() -> { + try { + String midsStr = TextUtils.join(",", mids); + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE mid IN (%s)", midsStr)).stepThis().dispose(); + if (date != 0) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE mid IN (%s) AND ttl > 0", midsStr)); + ArrayList arrayList = null; + while (cursor.next()) { + if (arrayList == null) { + arrayList = new ArrayList<>(); } - if (arrayList != null) { - emptyMessagesMedia(arrayList); - } - cursor.dispose(); + arrayList.add(cursor.intValue(0)); } - } catch (Exception e) { - FileLog.e(e); + if (arrayList != null) { + emptyMessagesMedia(arrayList); + } + cursor.dispose(); } + } catch (Exception e) { + FileLog.e(e); } }); } public void markMessagesAsRead(final SparseLongArray inbox, final SparseLongArray outbox, final SparseIntArray encryptedMessages, boolean useQueue) { if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - markMessagesAsReadInternal(inbox, outbox, encryptedMessages); - } - }); + storageQueue.postRunnable(() -> markMessagesAsReadInternal(inbox, outbox, encryptedMessages)); } else { markMessagesAsReadInternal(inbox, outbox, encryptedMessages); } @@ -5994,31 +5595,23 @@ public class MessagesStorage { if (messages.isEmpty()) { return; } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - String ids = TextUtils.join(",", messages); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id IN(%s)", ids)); - final ArrayList mids = new ArrayList<>(); - while (cursor.next()) { - mids.add(cursor.intValue(0)); - } - cursor.dispose(); - if (!mids.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, mids, 0); - } - }); - updateDialogsWithReadMessagesInternal(mids, null, null, null); - markMessagesAsDeletedInternal(mids, 0); - updateDialogsWithDeletedMessagesInternal(mids, null, 0); - } - } catch (Exception e) { - FileLog.e(e); + storageQueue.postRunnable(() -> { + try { + String ids = TextUtils.join(",", messages); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id IN(%s)", ids)); + final ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + mids.add(cursor.intValue(0)); } + cursor.dispose(); + if (!mids.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, mids, 0)); + updateDialogsWithReadMessagesInternal(mids, null, null, null); + markMessagesAsDeletedInternal(mids, 0); + updateDialogsWithDeletedMessagesInternal(mids, null, 0); + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -6332,12 +5925,7 @@ public class MessagesStorage { return; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - updateDialogsWithDeletedMessagesInternal(messages, additionalDialogsToUpdate, channelId); - } - }); + storageQueue.postRunnable(() -> updateDialogsWithDeletedMessagesInternal(messages, additionalDialogsToUpdate, channelId)); } else { updateDialogsWithDeletedMessagesInternal(messages, additionalDialogsToUpdate, channelId); } @@ -6348,12 +5936,7 @@ public class MessagesStorage { return null; } if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - markMessagesAsDeletedInternal(messages, channelId); - } - }); + storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(messages, channelId)); } else { return markMessagesAsDeletedInternal(messages, channelId); } @@ -6464,12 +6047,7 @@ public class MessagesStorage { public ArrayList markMessagesAsDeleted(final int channelId, final int mid, boolean useQueue) { if (useQueue) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - markMessagesAsDeletedInternal(channelId, mid); - } - }); + storageQueue.postRunnable(() -> markMessagesAsDeletedInternal(channelId, mid)); } else { return markMessagesAsDeletedInternal(channelId, mid); } @@ -6690,205 +6268,202 @@ public class MessagesStorage { } public void putMessages(final TLRPC.messages_Messages messages, final long dialog_id, final int load_type, final int max_id, final boolean createDialog) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int mentionCountUpdate = Integer.MAX_VALUE; - if (messages.messages.isEmpty()) { - if (load_type == 0) { - doneHolesInTable("messages_holes", dialog_id, max_id); - doneHolesInMedia(dialog_id, max_id, -1); - } - return; - } - database.beginTransaction(); - + storageQueue.postRunnable(() -> { + try { + int mentionCountUpdate = Integer.MAX_VALUE; + if (messages.messages.isEmpty()) { if (load_type == 0) { - int minId = messages.messages.get(messages.messages.size() - 1).id; - closeHolesInTable("messages_holes", dialog_id, minId, max_id); - closeHolesInMedia(dialog_id, minId, max_id, -1); - } else if (load_type == 1) { - int maxId = messages.messages.get(0).id; - closeHolesInTable("messages_holes", dialog_id, max_id, maxId); - closeHolesInMedia(dialog_id, max_id, maxId, -1); - } else if (load_type == 3 || load_type == 2 || load_type == 4) { - int maxId = max_id == 0 && load_type != 4 ? Integer.MAX_VALUE : messages.messages.get(0).id; - int minId = messages.messages.get(messages.messages.size() - 1).id; - closeHolesInTable("messages_holes", dialog_id, minId, maxId); - closeHolesInMedia(dialog_id, minId, maxId, -1); + doneHolesInTable("messages_holes", dialog_id, max_id); + doneHolesInMedia(dialog_id, max_id, -1); } - int count = messages.messages.size(); - - //load_type == 0 ? backward loading - //load_type == 1 ? forward loading - //load_type == 2 ? load from first unread - //load_type == 3 ? load around message - //load_type == 4 ? load around date - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)"); - SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); - SQLitePreparedStatement state5 = null; - TLRPC.Message botKeyboard = null; - int minChannelMessageId = Integer.MAX_VALUE; - int maxChannelMessageId = 0; - int channelId = 0; - for (int a = 0; a < count; a++) { - TLRPC.Message message = messages.messages.get(a); - - long messageId = message.id; - if (channelId == 0) { - channelId = message.to_id.channel_id; - } - if (message.to_id.channel_id != 0) { - messageId |= ((long) channelId) << 32; - } - - if (load_type == -2) { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, data, ttl, mention, read_state, send_state FROM messages WHERE mid = %d", messageId)); - boolean exist; - if (exist = cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(1); - if (data != null) { - TLRPC.Message oldMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - oldMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - int send_state = cursor.intValue(5); - if (oldMessage != null && send_state != 3) { - message.attachPath = oldMessage.attachPath; - message.ttl = cursor.intValue(2); - } - } - boolean oldMention = cursor.intValue(3) != 0; - int readState = cursor.intValue(4); - if (oldMention != message.mentioned) { - if (mentionCountUpdate == Integer.MAX_VALUE) { - SQLiteCursor cursor2 = database.queryFinalized("SELECT unread_count_i FROM dialogs WHERE did = " + dialog_id); - if (cursor2.next()) { - mentionCountUpdate = cursor2.intValue(0); - } - cursor2.dispose(); - } - if (oldMention) { - if (readState <= 1) { - mentionCountUpdate--; - } - } else { - if (message.media_unread) { - mentionCountUpdate++; - } - } - } - } - cursor.dispose(); - if (!exist) { - continue; - } - } - - if (a == 0 && createDialog) { - int pinned = 0; - int mentions = 0; - int flags = 0; - SQLiteCursor cursor = database.queryFinalized("SELECT pinned, unread_count_i, flags FROM dialogs WHERE did = " + dialog_id); - if (cursor.next()) { - pinned = cursor.intValue(0); - mentions = cursor.intValue(1); - flags = cursor.intValue(2); - } - cursor.dispose(); - - SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - state3.bindLong(1, dialog_id); - state3.bindInteger(2, message.date); - state3.bindInteger(3, 0); - state3.bindLong(4, messageId); - state3.bindInteger(5, message.id); - state3.bindInteger(6, 0); - state3.bindLong(7, messageId); - state3.bindInteger(8, mentions); - state3.bindInteger(9, messages.pts); - state3.bindInteger(10, message.date); - state3.bindInteger(11, pinned); - state3.bindInteger(12, flags); - state3.step(); - state3.dispose(); - } - - fixUnsupportedMedia(message); - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); - message.serializeToStream(data); - state.bindLong(1, messageId); - state.bindLong(2, dialog_id); - state.bindInteger(3, MessageObject.getUnreadFlags(message)); - state.bindInteger(4, message.send_state); - state.bindInteger(5, message.date); - state.bindByteBuffer(6, data); - state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); - state.bindInteger(8, message.ttl); - if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { - state.bindInteger(9, message.views); - } else { - state.bindInteger(9, getMessageMediaType(message)); - } - state.bindInteger(10, 0); - state.bindInteger(11, message.mentioned ? 1 : 0); - state.step(); - - if (DataQuery.canAddMessageToMedia(message)) { - state2.requery(); - state2.bindLong(1, messageId); - state2.bindLong(2, dialog_id); - state2.bindInteger(3, message.date); - state2.bindInteger(4, DataQuery.getMediaType(message)); - state2.bindByteBuffer(5, data); - state2.step(); - } - data.reuse(); - if (message.media instanceof TLRPC.TL_messageMediaWebPage) { - if (state5 == null) { - state5 = database.executeFast("REPLACE INTO webpage_pending VALUES(?, ?)"); - } - state5.requery(); - state5.bindLong(1, message.media.webpage.id); - state5.bindLong(2, messageId); - state5.step(); - } - - if (load_type == 0 && isValidKeyboardToSave(message)) { - if (botKeyboard == null || botKeyboard.id < message.id) { - botKeyboard = message; - } - } - } - state.dispose(); - state2.dispose(); - if (state5 != null) { - state5.dispose(); - } - if (botKeyboard != null) { - DataQuery.getInstance(currentAccount).putBotKeyboard(dialog_id, botKeyboard); - } - - putUsersInternal(messages.users); - putChatsInternal(messages.chats); - - if (mentionCountUpdate != Integer.MAX_VALUE) { - database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", mentionCountUpdate, dialog_id)).stepThis().dispose(); - LongSparseArray sparseArray = new LongSparseArray<>(1); - sparseArray.put(dialog_id, mentionCountUpdate); - MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); - } - - database.commitTransaction(); - - if (createDialog) { - updateDialogsWithDeletedMessages(new ArrayList(), null, false, channelId); - } - } catch (Exception e) { - FileLog.e(e); + return; } + database.beginTransaction(); + + if (load_type == 0) { + int minId = messages.messages.get(messages.messages.size() - 1).id; + closeHolesInTable("messages_holes", dialog_id, minId, max_id); + closeHolesInMedia(dialog_id, minId, max_id, -1); + } else if (load_type == 1) { + int maxId = messages.messages.get(0).id; + closeHolesInTable("messages_holes", dialog_id, max_id, maxId); + closeHolesInMedia(dialog_id, max_id, maxId, -1); + } else if (load_type == 3 || load_type == 2 || load_type == 4) { + int maxId = max_id == 0 && load_type != 4 ? Integer.MAX_VALUE : messages.messages.get(0).id; + int minId = messages.messages.get(messages.messages.size() - 1).id; + closeHolesInTable("messages_holes", dialog_id, minId, maxId); + closeHolesInMedia(dialog_id, minId, maxId, -1); + } + int count = messages.messages.size(); + + //load_type == 0 ? backward loading + //load_type == 1 ? forward loading + //load_type == 2 ? load from first unread + //load_type == 3 ? load around message + //load_type == 4 ? load around date + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)"); + SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state5 = null; + TLRPC.Message botKeyboard = null; + int minChannelMessageId = Integer.MAX_VALUE; + int maxChannelMessageId = 0; + int channelId = 0; + for (int a = 0; a < count; a++) { + TLRPC.Message message = messages.messages.get(a); + + long messageId = message.id; + if (channelId == 0) { + channelId = message.to_id.channel_id; + } + if (message.to_id.channel_id != 0) { + messageId |= ((long) channelId) << 32; + } + + if (load_type == -2) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, data, ttl, mention, read_state, send_state FROM messages WHERE mid = %d", messageId)); + boolean exist; + if (exist = cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(1); + if (data != null) { + TLRPC.Message oldMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + oldMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + int send_state = cursor.intValue(5); + if (oldMessage != null && send_state != 3) { + message.attachPath = oldMessage.attachPath; + message.ttl = cursor.intValue(2); + } + } + boolean oldMention = cursor.intValue(3) != 0; + int readState = cursor.intValue(4); + if (oldMention != message.mentioned) { + if (mentionCountUpdate == Integer.MAX_VALUE) { + SQLiteCursor cursor2 = database.queryFinalized("SELECT unread_count_i FROM dialogs WHERE did = " + dialog_id); + if (cursor2.next()) { + mentionCountUpdate = cursor2.intValue(0); + } + cursor2.dispose(); + } + if (oldMention) { + if (readState <= 1) { + mentionCountUpdate--; + } + } else { + if (message.media_unread) { + mentionCountUpdate++; + } + } + } + } + cursor.dispose(); + if (!exist) { + continue; + } + } + + if (a == 0 && createDialog) { + int pinned = 0; + int mentions = 0; + int flags = 0; + SQLiteCursor cursor = database.queryFinalized("SELECT pinned, unread_count_i, flags FROM dialogs WHERE did = " + dialog_id); + if (cursor.next()) { + pinned = cursor.intValue(0); + mentions = cursor.intValue(1); + flags = cursor.intValue(2); + } + cursor.dispose(); + + SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state3.bindLong(1, dialog_id); + state3.bindInteger(2, message.date); + state3.bindInteger(3, 0); + state3.bindLong(4, messageId); + state3.bindInteger(5, message.id); + state3.bindInteger(6, 0); + state3.bindLong(7, messageId); + state3.bindInteger(8, mentions); + state3.bindInteger(9, messages.pts); + state3.bindInteger(10, message.date); + state3.bindInteger(11, pinned); + state3.bindInteger(12, flags); + state3.step(); + state3.dispose(); + } + + fixUnsupportedMedia(message); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state.bindLong(1, messageId); + state.bindLong(2, dialog_id); + state.bindInteger(3, MessageObject.getUnreadFlags(message)); + state.bindInteger(4, message.send_state); + state.bindInteger(5, message.date); + state.bindByteBuffer(6, data); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); + state.bindInteger(8, message.ttl); + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + state.bindInteger(9, message.views); + } else { + state.bindInteger(9, getMessageMediaType(message)); + } + state.bindInteger(10, 0); + state.bindInteger(11, message.mentioned ? 1 : 0); + state.step(); + + if (DataQuery.canAddMessageToMedia(message)) { + state2.requery(); + state2.bindLong(1, messageId); + state2.bindLong(2, dialog_id); + state2.bindInteger(3, message.date); + state2.bindInteger(4, DataQuery.getMediaType(message)); + state2.bindByteBuffer(5, data); + state2.step(); + } + data.reuse(); + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (state5 == null) { + state5 = database.executeFast("REPLACE INTO webpage_pending VALUES(?, ?)"); + } + state5.requery(); + state5.bindLong(1, message.media.webpage.id); + state5.bindLong(2, messageId); + state5.step(); + } + + if (load_type == 0 && isValidKeyboardToSave(message)) { + if (botKeyboard == null || botKeyboard.id < message.id) { + botKeyboard = message; + } + } + } + state.dispose(); + state2.dispose(); + if (state5 != null) { + state5.dispose(); + } + if (botKeyboard != null) { + DataQuery.getInstance(currentAccount).putBotKeyboard(dialog_id, botKeyboard); + } + + putUsersInternal(messages.users); + putChatsInternal(messages.chats); + + if (mentionCountUpdate != Integer.MAX_VALUE) { + database.executeFast(String.format(Locale.US, "UPDATE dialogs SET unread_count_i = %d WHERE did = %d", mentionCountUpdate, dialog_id)).stepThis().dispose(); + LongSparseArray sparseArray = new LongSparseArray<>(1); + sparseArray.put(dialog_id, mentionCountUpdate); + MessagesController.getInstance(currentAccount).processDialogsUpdateRead(null, sparseArray); + } + + database.commitTransaction(); + + if (createDialog) { + updateDialogsWithDeletedMessages(new ArrayList<>(), null, false, channelId); + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -6977,171 +6552,168 @@ public class MessagesStorage { } public void getDialogs(final int offset, final int count) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - TLRPC.messages_Dialogs dialogs = new TLRPC.TL_messages_dialogs(); - ArrayList encryptedChats = new ArrayList<>(); - try { - ArrayList usersToLoad = new ArrayList<>(); - usersToLoad.add(UserConfig.getInstance(currentAccount).getClientUserId()); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList encryptedToLoad = new ArrayList<>(); - ArrayList replyMessages = new ArrayList<>(); - LongSparseArray replyMessageOwners = new LongSparseArray<>(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.pts, d.inbox_max, d.outbox_max, m.replydata, d.pinned, d.unread_count_i, d.flags FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.pinned DESC, d.date DESC LIMIT %d,%d", offset, count)); - while (cursor.next()) { - TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); - dialog.id = cursor.longValue(0); - dialog.top_message = cursor.intValue(1); - dialog.unread_count = cursor.intValue(2); - dialog.last_message_date = cursor.intValue(3); - dialog.pts = cursor.intValue(10); - dialog.flags = dialog.pts == 0 || (int) dialog.id > 0 ? 0 : 1; - dialog.read_inbox_max_id = cursor.intValue(11); - dialog.read_outbox_max_id = cursor.intValue(12); - dialog.pinnedNum = cursor.intValue(14); - dialog.pinned = dialog.pinnedNum != 0; - dialog.unread_mentions_count = cursor.intValue(15); - int dialog_flags = cursor.intValue(16); - dialog.unread_mark = (dialog_flags & 1) != 0; - long flags = cursor.longValue(8); - int low_flags = (int) flags; - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - if ((low_flags & 1) != 0) { - dialog.notify_settings.mute_until = (int) (flags >> 32); - if (dialog.notify_settings.mute_until == 0) { - dialog.notify_settings.mute_until = Integer.MAX_VALUE; + storageQueue.postRunnable(() -> { + TLRPC.messages_Dialogs dialogs = new TLRPC.TL_messages_dialogs(); + ArrayList encryptedChats = new ArrayList<>(); + try { + ArrayList usersToLoad = new ArrayList<>(); + usersToLoad.add(UserConfig.getInstance(currentAccount).getClientUserId()); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedToLoad = new ArrayList<>(); + ArrayList replyMessages = new ArrayList<>(); + LongSparseArray replyMessageOwners = new LongSparseArray<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.pts, d.inbox_max, d.outbox_max, m.replydata, d.pinned, d.unread_count_i, d.flags FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.pinned DESC, d.date DESC LIMIT %d,%d", offset, count)); + while (cursor.next()) { + TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); + dialog.id = cursor.longValue(0); + dialog.top_message = cursor.intValue(1); + dialog.unread_count = cursor.intValue(2); + dialog.last_message_date = cursor.intValue(3); + dialog.pts = cursor.intValue(10); + dialog.flags = dialog.pts == 0 || (int) dialog.id > 0 ? 0 : 1; + dialog.read_inbox_max_id = cursor.intValue(11); + dialog.read_outbox_max_id = cursor.intValue(12); + dialog.pinnedNum = cursor.intValue(14); + dialog.pinned = dialog.pinnedNum != 0; + dialog.unread_mentions_count = cursor.intValue(15); + int dialog_flags = cursor.intValue(16); + dialog.unread_mark = (dialog_flags & 1) != 0; + long flags = cursor.longValue(8); + int low_flags = (int) flags; + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + if ((low_flags & 1) != 0) { + dialog.notify_settings.mute_until = (int) (flags >> 32); + if (dialog.notify_settings.mute_until == 0) { + dialog.notify_settings.mute_until = Integer.MAX_VALUE; + } + } + dialogs.dialogs.add(dialog); + + NativeByteBuffer data = cursor.byteBufferValue(4); + if (data != null) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message != null) { + MessageObject.setUnreadFlags(message, cursor.intValue(5)); + message.id = cursor.intValue(6); + int date = cursor.intValue(9); + if (date != 0) { + dialog.last_message_date = date; + } + message.send_state = cursor.intValue(7); + message.dialog_id = dialog.id; + dialogs.messages.add(message); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + try { + if (message.reply_to_msg_id != 0 && ( + message.action instanceof TLRPC.TL_messageActionPinMessage || + message.action instanceof TLRPC.TL_messageActionPaymentSent || + message.action instanceof TLRPC.TL_messageActionGameScore)) { + if (!cursor.isNull(13)) { + data = cursor.byteBufferValue(13); + if (data != null) { + message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + if (message.replyMessage != null) { + if (MessageObject.isMegagroup(message)) { + message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); + } + } + } + if (message.replyMessage == null) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + replyMessageOwners.put(dialog.id, message); + } + } + } catch (Exception e) { + FileLog.e(e); } } - dialogs.dialogs.add(dialog); + } - NativeByteBuffer data = cursor.byteBufferValue(4); + int lower_id = (int) dialog.id; + int high_id = (int) (dialog.id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + if (!chatsToLoad.contains(lower_id)) { + chatsToLoad.add(lower_id); + } + } else { + if (lower_id > 0) { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } else { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } + } + } else { + if (!encryptedToLoad.contains(high_id)) { + encryptedToLoad.add(high_id); + } + } + } + cursor.dispose(); + + if (!replyMessages.isEmpty()) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); data.reuse(); - if (message != null) { - MessageObject.setUnreadFlags(message, cursor.intValue(5)); - message.id = cursor.intValue(6); - int date = cursor.intValue(9); - if (date != 0) { - dialog.last_message_date = date; - } - message.send_state = cursor.intValue(7); - message.dialog_id = dialog.id; - dialogs.messages.add(message); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = cursor.longValue(3); - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - try { - if (message.reply_to_msg_id != 0 && ( - message.action instanceof TLRPC.TL_messageActionPinMessage || - message.action instanceof TLRPC.TL_messageActionPaymentSent || - message.action instanceof TLRPC.TL_messageActionGameScore)) { - if (!cursor.isNull(13)) { - data = cursor.byteBufferValue(13); - if (data != null) { - message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.replyMessage.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - if (message.replyMessage != null) { - if (MessageObject.isMegagroup(message)) { - message.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); - } - } - } - if (message.replyMessage == null) { - long messageId = message.reply_to_msg_id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; - } - if (!replyMessages.contains(messageId)) { - replyMessages.add(messageId); - } - replyMessageOwners.put(dialog.id, message); - } - } - } catch (Exception e) { - FileLog.e(e); + TLRPC.Message owner = replyMessageOwners.get(message.dialog_id); + if (owner != null) { + owner.replyMessage = message; + message.dialog_id = owner.dialog_id; + if (MessageObject.isMegagroup(owner)) { + owner.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } } } - - int lower_id = (int) dialog.id; - int high_id = (int) (dialog.id >> 32); - if (lower_id != 0) { - if (high_id == 1) { - if (!chatsToLoad.contains(lower_id)) { - chatsToLoad.add(lower_id); - } - } else { - if (lower_id > 0) { - if (!usersToLoad.contains(lower_id)) { - usersToLoad.add(lower_id); - } - } else { - if (!chatsToLoad.contains(-lower_id)) { - chatsToLoad.add(-lower_id); - } - } - } - } else { - if (!encryptedToLoad.contains(high_id)) { - encryptedToLoad.add(high_id); - } - } } cursor.dispose(); - - if (!replyMessages.isEmpty()) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.dialog_id = cursor.longValue(3); - - addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - - TLRPC.Message owner = replyMessageOwners.get(message.dialog_id); - if (owner != null) { - owner.replyMessage = message; - message.dialog_id = owner.dialog_id; - if (MessageObject.isMegagroup(owner)) { - owner.replyMessage.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } - } - } - cursor.dispose(); - } - - if (!encryptedToLoad.isEmpty()) { - getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); - } - - if (!chatsToLoad.isEmpty()) { - getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); - } - if (!usersToLoad.isEmpty()) { - getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); - } - MessagesController.getInstance(currentAccount).processLoadedDialogs(dialogs, encryptedChats, offset, count, 1, false, false, true); - } catch (Exception e) { - dialogs.dialogs.clear(); - dialogs.users.clear(); - dialogs.chats.clear(); - encryptedChats.clear(); - FileLog.e(e); - MessagesController.getInstance(currentAccount).processLoadedDialogs(dialogs, encryptedChats, 0, 100, 1, true, false, true); } + + if (!encryptedToLoad.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); + } + + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); + } + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); + } + MessagesController.getInstance(currentAccount).processLoadedDialogs(dialogs, encryptedChats, offset, count, 1, false, false, true); + } catch (Exception e) { + dialogs.dialogs.clear(); + dialogs.users.clear(); + dialogs.chats.clear(); + encryptedChats.clear(); + FileLog.e(e); + MessagesController.getInstance(currentAccount).processLoadedDialogs(dialogs, encryptedChats, 0, 100, 1, true, false, true); } }); } @@ -7302,124 +6874,43 @@ public class MessagesStorage { } public void unpinAllDialogsExceptNew(final ArrayList dids) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - ArrayList unpinnedDialogs = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE pinned != 0 AND did NOT IN (%s)", TextUtils.join(",", dids))); - while (cursor.next()) { - long did = cursor.longValue(0); - if ((int) did != 0) { - unpinnedDialogs.add(cursor.longValue(0)); - } + storageQueue.postRunnable(() -> { + try { + ArrayList unpinnedDialogs = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE pinned != 0 AND did NOT IN (%s)", TextUtils.join(",", dids))); + while (cursor.next()) { + long did = cursor.longValue(0); + if ((int) did != 0) { + unpinnedDialogs.add(cursor.longValue(0)); } - cursor.dispose(); - if (!unpinnedDialogs.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?"); - for (int a = 0; a < unpinnedDialogs.size(); a++) { - long did = unpinnedDialogs.get(a); - state.requery(); - state.bindInteger(1, 0); - state.bindLong(2, did); - state.step(); - } - state.dispose(); - } - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + if (!unpinnedDialogs.isEmpty()) { + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?"); + for (int a = 0; a < unpinnedDialogs.size(); a++) { + long did = unpinnedDialogs.get(a); + state.requery(); + state.bindInteger(1, 0); + state.bindLong(2, did); + state.step(); + } + state.dispose(); + } + } catch (Exception e) { + FileLog.e(e); } }); } public void setDialogUnread(final long did, final boolean unread) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - int flags = 0; - SQLiteCursor cursor = null; - try { - cursor = database.queryFinalized("SELECT flags FROM dialogs WHERE did = " + did); - if (cursor.next()) { - flags = cursor.intValue(0); - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } - } - - if (unread) { - flags |= 1; - } else { - flags &= ~1; - } - - SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET flags = ? WHERE did = ?"); - state.bindInteger(1, flags); - state.bindLong(2, did); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void setDialogPinned(final long did, final int pinned) { - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?"); - state.bindInteger(1, pinned); - state.bindLong(2, did); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public void putDialogs(final TLRPC.messages_Dialogs dialogs, final int check) { - if (dialogs.dialogs.isEmpty()) { - return; - } - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - putDialogsInternal(dialogs, check); - try { - loadUnreadMessages(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } - - public int getDialogReadMax(final boolean outbox, final long dialog_id) { - final CountDownLatch countDownLatch = new CountDownLatch(1); - final Integer[] max = new Integer[]{0}; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { + storageQueue.postRunnable(() -> { + try { + int flags = 0; SQLiteCursor cursor = null; try { - if (outbox) { - cursor = database.queryFinalized("SELECT outbox_max FROM dialogs WHERE did = " + dialog_id); - } else { - cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + dialog_id); - } + cursor = database.queryFinalized("SELECT flags FROM dialogs WHERE did = " + did); if (cursor.next()) { - max[0] = cursor.intValue(0); + flags = cursor.intValue(0); } } catch (Exception e) { FileLog.e(e); @@ -7428,9 +6919,75 @@ public class MessagesStorage { cursor.dispose(); } } - countDownLatch.countDown(); + + if (unread) { + flags |= 1; + } else { + flags &= ~1; + } + + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET flags = ? WHERE did = ?"); + state.bindInteger(1, flags); + state.bindLong(2, did); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); + } + + public void setDialogPinned(final long did, final int pinned) { + storageQueue.postRunnable(() -> { + try { + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?"); + state.bindInteger(1, pinned); + state.bindLong(2, did); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public void putDialogs(final TLRPC.messages_Dialogs dialogs, final int check) { + if (dialogs.dialogs.isEmpty()) { + return; + } + storageQueue.postRunnable(() -> { + putDialogsInternal(dialogs, check); + try { + loadUnreadMessages(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + + public int getDialogReadMax(final boolean outbox, final long dialog_id) { + final CountDownLatch countDownLatch = new CountDownLatch(1); + final Integer[] max = new Integer[]{0}; + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + if (outbox) { + cursor = database.queryFinalized("SELECT outbox_max FROM dialogs WHERE did = " + dialog_id); + } else { + cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + dialog_id); + } + if (cursor.next()) { + max[0] = cursor.intValue(0); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + countDownLatch.countDown(); + }); try { countDownLatch.await(); } catch (Exception e) { @@ -7442,30 +6999,27 @@ public class MessagesStorage { public int getChannelPtsSync(final int channelId) { final CountDownLatch countDownLatch = new CountDownLatch(1); final Integer[] pts = new Integer[]{0}; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - SQLiteCursor cursor = null; - try { - cursor = database.queryFinalized("SELECT pts FROM dialogs WHERE did = " + (-channelId)); - if (cursor.next()) { - pts[0] = cursor.intValue(0); - } - } catch (Exception e) { - FileLog.e(e); - } finally { - if (cursor != null) { - cursor.dispose(); - } + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT pts FROM dialogs WHERE did = " + (-channelId)); + if (cursor.next()) { + pts[0] = cursor.intValue(0); } - try { - if (countDownLatch != null) { - countDownLatch.countDown(); - } - } catch (Exception e) { - FileLog.e(e); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); } } + try { + if (countDownLatch != null) { + countDownLatch.countDown(); + } + } catch (Exception e) { + FileLog.e(e); + } }); try { countDownLatch.await(); @@ -7478,12 +7032,9 @@ public class MessagesStorage { public TLRPC.User getUserSync(final int user_id) { final CountDownLatch countDownLatch = new CountDownLatch(1); final TLRPC.User[] user = new TLRPC.User[1]; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - user[0] = getUser(user_id); - countDownLatch.countDown(); - } + storageQueue.postRunnable(() -> { + user[0] = getUser(user_id); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -7496,12 +7047,9 @@ public class MessagesStorage { public TLRPC.Chat getChatSync(final int chat_id) { final CountDownLatch countDownLatch = new CountDownLatch(1); final TLRPC.Chat[] chat = new TLRPC.Chat[1]; - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - chat[0] = getChat(chat_id); - countDownLatch.countDown(); - } + storageQueue.postRunnable(() -> { + chat[0] = getChat(chat_id); + countDownLatch.countDown(); }); try { countDownLatch.await(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MrzRecognizer.java b/TMessagesProj/src/main/java/org/telegram/messenger/MrzRecognizer.java index 9fd477ee7..d19ef6271 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MrzRecognizer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MrzRecognizer.java @@ -62,6 +62,7 @@ public class MrzRecognizer { } res.firstName=capitalize(code.driverLicense.firstName); res.lastName=capitalize(code.driverLicense.lastName); + res.middleName=capitalize(code.driverLicense.middleName); res.number=code.driverLicense.licenseNumber; if(code.driverLicense.gender!=null){ switch(code.driverLicense.gender){ @@ -114,6 +115,7 @@ public class MrzRecognizer { res.expiryDay=Integer.parseInt(data[2].substring(6)); res.lastName=capitalize(cyrillicToLatin(data[3])); res.firstName=capitalize(cyrillicToLatin(data[4])); + res.middleName=capitalize(cyrillicToLatin(data[5])); res.birthYear=Integer.parseInt(data[6].substring(0, 4)); res.birthMonth=Integer.parseInt(data[6].substring(4, 6)); res.birthDay=Integer.parseInt(data[6].substring(6)); @@ -283,7 +285,10 @@ public class MrzRecognizer { // Russian internal passports use transliteration for the name and have a number one digit longer than fits into the standard MRZ format if ("RUS".equals(result.issuingCountry) && mrzLines[0].charAt(1) == 'N') { result.type=Result.TYPE_INTERNAL_PASSPORT; - result.firstName = cyrillicToLatin(russianPassportTranslit(result.firstName.split(" ")[0])); + String[] names=result.firstName.split(" "); + result.firstName = cyrillicToLatin(russianPassportTranslit(names[0])); + if(names.length>1) + result.middleName=cyrillicToLatin(russianPassportTranslit(names[1])); result.lastName = cyrillicToLatin(russianPassportTranslit(result.lastName)); if (result.number != null) result.number = result.number.substring(0, 3) + mrzLines[1].charAt(28) + result.number.substring(3); @@ -293,6 +298,7 @@ public class MrzRecognizer { } result.lastName = capitalize(result.lastName); result.firstName = capitalize(result.firstName); + result.middleName = capitalize(result.middleName); } } else if (type == 'I' || type == 'A' || type == 'C') { // id result.type = Result.TYPE_ID; @@ -362,7 +368,11 @@ public class MrzRecognizer { } result.firstName = capitalize(result.firstName.replace('0', 'O').replace('8', 'B')); result.lastName = capitalize(result.lastName.replace('0', 'O').replace('8', 'B')); + } else { + return null; } + if(TextUtils.isEmpty(result.firstName) && TextUtils.isEmpty(result.lastName)) + return null; result.issuingCountry = countries.get(result.issuingCountry); result.nationality = countries.get(result.nationality); return result; @@ -384,6 +394,8 @@ public class MrzRecognizer { } private static String capitalize(String s) { + if(s==null) + return null; char[] chars = s.toCharArray(); boolean prevIsSpace = true; for (int i = 0; i < chars.length; i++) { @@ -472,6 +484,8 @@ public class MrzRecognizer { return 0; if (c == 'I') return 1; + if (c == 'B') + return 8; return c - '0'; } @@ -749,6 +763,7 @@ public class MrzRecognizer { public int type; public String firstName; public String lastName; + public String middleName; public String number; public int expiryYear, expiryMonth, expiryDay; public int birthYear, birthMonth, birthDay; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java index 3a81a13ee..bbd4f4bce 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java @@ -31,6 +31,8 @@ import android.text.TextUtils; import android.view.View; import android.widget.RemoteViews; +import com.google.android.exoplayer2.C; + import org.telegram.messenger.audioinfo.AudioInfo; import org.telegram.ui.LaunchActivity; @@ -48,11 +50,12 @@ public class MusicPlayerService extends Service implements NotificationCenter.No private AudioManager audioManager; private static boolean supportBigNotifications = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; - private static boolean supportLockScreenControls = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; + private static boolean supportLockScreenControls = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || !TextUtils.isEmpty(AndroidUtilities.getSystemProperty("ro.miui.ui.version.code")); private MediaSession mediaSession; private PlaybackState.Builder playbackState; private Bitmap albumArtPlaceholder; + private int notificationMessageID; @Override public IBinder onBind(Intent intent) { @@ -63,7 +66,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No public void onCreate() { audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - NotificationCenter.getInstance(a).addObserver(this, NotificationCenter.messagePlayingProgressDidChanged); + NotificationCenter.getInstance(a).addObserver(this, NotificationCenter.messagePlayingDidSeek); NotificationCenter.getInstance(a).addObserver(this, NotificationCenter.messagePlayingPlayStateChanged); } @@ -162,7 +165,6 @@ public class MusicPlayerService extends Service implements NotificationCenter.No Notification notification; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Bitmap albumArt = audioInfo != null ? audioInfo.getSmallCover() : null; Bitmap fullAlbumArt = audioInfo != null ? audioInfo.getCover() : null; boolean isPlaying = !MediaController.getInstance().isMessagePaused(); @@ -188,6 +190,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No .setMediaSession(mediaSession.getSessionToken()) .setShowActionsInCompactView(0, 1, 2)); if (Build.VERSION.SDK_INT >= 26) { + NotificationsController.checkOtherNotificationsChannel(); bldr.setChannelId(NotificationsController.OTHER_NOTIFICATIONS_CHANNEL); } if (albumArt != null) { @@ -320,17 +323,59 @@ public class MusicPlayerService extends Service implements NotificationCenter.No } if (remoteControlClient != null) { - RemoteControlClient.MetadataEditor metadataEditor = remoteControlClient.editMetadata(true); - metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, authorName); - metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, songName); - if (audioInfo != null && audioInfo.getCover() != null) { - try { - metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover()); - } catch (Throwable e) { - FileLog.e(e); + int currentID=MediaController.getInstance().getPlayingMessageObject().getId(); + if(notificationMessageID!=currentID){ + notificationMessageID=currentID; + RemoteControlClient.MetadataEditor metadataEditor=remoteControlClient.editMetadata(true); + metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, authorName); + metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, songName); + if(audioInfo!=null && !TextUtils.isEmpty(audioInfo.getAlbum())) + metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, audioInfo.getAlbum()); + metadataEditor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, MediaController.getInstance().getPlayingMessageObject().audioPlayerDuration*1000L); + if(audioInfo!=null && audioInfo.getCover()!=null){ + try{ + metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover()); + }catch(Throwable e){ + FileLog.e(e); + } + } + metadataEditor.apply(); + AndroidUtilities.runOnUIThread(new Runnable(){ + @Override + public void run(){ + if(remoteControlClient==null) + return; + if(MediaController.getInstance().getPlayingMessageObject().audioPlayerDuration==C.TIME_UNSET){ + AndroidUtilities.runOnUIThread(this, 500); + return; + } + RemoteControlClient.MetadataEditor metadataEditor=remoteControlClient.editMetadata(false); + metadataEditor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, MediaController.getInstance().getPlayingMessageObject().audioPlayerDuration*1000L); + metadataEditor.apply(); + if(Build.VERSION.SDK_INT>=18){ + remoteControlClient.setPlaybackState(MediaController.getInstance().isMessagePaused() ? RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING, + Math.max(MediaController.getInstance().getPlayingMessageObject().audioProgressSec*1000L, 100), + MediaController.getInstance().isMessagePaused() ? 0f : 1f); + }else{ + remoteControlClient.setPlaybackState(MediaController.getInstance().isMessagePaused() ? RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING); + } + } + }, 1000); + } + if(MediaController.getInstance().isDownloadingCurrentMessage()){ + remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_BUFFERING); + }else{ + RemoteControlClient.MetadataEditor metadataEditor=remoteControlClient.editMetadata(false); + metadataEditor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, MediaController.getInstance().getPlayingMessageObject().audioPlayerDuration*1000L); + metadataEditor.apply(); + if(Build.VERSION.SDK_INT>=18){ + remoteControlClient.setPlaybackState(MediaController.getInstance().isMessagePaused() ? RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING, + Math.max(MediaController.getInstance().getPlayingMessageObject().audioProgressSec*1000L, 100), + MediaController.getInstance().isMessagePaused() ? 0f : 1f); + }else{ + remoteControlClient.setPlaybackState(MediaController.getInstance().isMessagePaused() ? RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING); } } - metadataEditor.apply(); } } @@ -361,7 +406,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No mediaSession.release(); } for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - NotificationCenter.getInstance(a).removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged); + NotificationCenter.getInstance(a).removeObserver(this, NotificationCenter.messagePlayingDidSeek); NotificationCenter.getInstance(a).removeObserver(this, NotificationCenter.messagePlayingPlayStateChanged); } } @@ -375,6 +420,14 @@ public class MusicPlayerService extends Service implements NotificationCenter.No } else { stopSelf(); } + }else if(id==NotificationCenter.messagePlayingDidSeek){ + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if(remoteControlClient!=null && Build.VERSION.SDK_INT>=18){ + long progress=Math.round(messageObject.audioPlayerDuration*(float)args[1])*1000L; + remoteControlClient.setPlaybackState(MediaController.getInstance().isMessagePaused() ? RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING, + progress, + MediaController.getInstance().isMessagePaused() ? 0f : 1f); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java index e495b76a7..53b18d016 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -24,7 +24,7 @@ import java.util.zip.ZipFile; public class NativeLoader { - private final static int LIB_VERSION = 28; + private final static int LIB_VERSION = 29; 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"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index e4a3b5351..ac198ba25 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -106,6 +106,7 @@ public class NotificationCenter { public static final int messagePlayingDidReset = totalEvents++; public static final int messagePlayingPlayStateChanged = totalEvents++; public static final int messagePlayingDidStarted = totalEvents++; + public static final int messagePlayingDidSeek = totalEvents++; public static final int recordProgressChanged = totalEvents++; public static final int recordStarted = totalEvents++; public static final int recordStartError = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index ac0f86d0c..d292a6359 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -10,6 +10,7 @@ package org.telegram.messenger; import android.annotation.SuppressLint; import android.annotation.TargetApi; +import android.app.Activity; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationChannel; @@ -20,7 +21,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.ImageDecoder; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.drawable.BitmapDrawable; import android.media.AudioAttributes; import android.media.AudioManager; @@ -32,8 +40,10 @@ import android.os.SystemClock; import android.provider.Settings; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.app.Person; import android.support.v4.app.RemoteInput; import android.support.v4.content.FileProvider; +import android.support.v4.graphics.drawable.IconCompat; import android.text.TextUtils; import android.util.LongSparseArray; import android.util.SparseArray; @@ -44,8 +54,6 @@ import org.json.JSONException; import org.json.JSONObject; import org.telegram.messenger.support.SparseLongArray; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PopupNotificationActivity; @@ -58,7 +66,7 @@ import java.util.List; public class NotificationsController { public static final String EXTRA_VOICE_REPLY = "extra_voice_reply"; - public static final String OTHER_NOTIFICATIONS_CHANNEL = "Other3"; + public static String OTHER_NOTIFICATIONS_CHANNEL = null; private static DispatchQueue notificationsQueue = new DispatchQueue("notificationsQueue"); private ArrayList pushMessages = new ArrayList<>(); @@ -113,11 +121,7 @@ public class NotificationsController { if (Build.VERSION.SDK_INT >= 26 && ApplicationLoader.applicationContext != null) { notificationManager = NotificationManagerCompat.from(ApplicationLoader.applicationContext); systemNotificationManager = (NotificationManager) ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); - NotificationChannel notificationChannel = new NotificationChannel(OTHER_NOTIFICATIONS_CHANNEL, "Other", NotificationManager.IMPORTANCE_DEFAULT); - notificationChannel.enableLights(false); - notificationChannel.enableVibration(false); - notificationChannel.setSound(null, null); - systemNotificationManager.createNotificationChannel(notificationChannel); + checkOtherNotificationsChannel(); } audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE); } @@ -168,75 +172,100 @@ public class NotificationsController { FileLog.e(e); } - notificationDelayRunnable = new Runnable() { - @Override - public void run() { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("delay reached"); - } - if (!delayedPushMessages.isEmpty()) { - showOrUpdateNotification(true); - delayedPushMessages.clear(); - } else if (lastNotificationIsNoData) { - notificationManager.cancel(notificationId); - } - try { - if (notificationDelayWakelock.isHeld()) { - notificationDelayWakelock.release(); - } - } catch (Exception e) { - FileLog.e(e); + notificationDelayRunnable = () -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("delay reached"); + } + if (!delayedPushMessages.isEmpty()) { + showOrUpdateNotification(true); + delayedPushMessages.clear(); + } else if (lastNotificationIsNoData) { + notificationManager.cancel(notificationId); + } + try { + if (notificationDelayWakelock.isHeld()) { + notificationDelayWakelock.release(); } + } catch (Exception e) { + FileLog.e(e); } }; } + public static void checkOtherNotificationsChannel() { + if (Build.VERSION.SDK_INT < 26) { + return; + } + SharedPreferences preferences = null; + if (OTHER_NOTIFICATIONS_CHANNEL == null) { + preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + OTHER_NOTIFICATIONS_CHANNEL = preferences.getString("OtherKey", "Other3"); + } + NotificationChannel notificationChannel = systemNotificationManager.getNotificationChannel(OTHER_NOTIFICATIONS_CHANNEL); + if (notificationChannel != null && notificationChannel.getImportance() == NotificationManager.IMPORTANCE_NONE) { + systemNotificationManager.deleteNotificationChannel(OTHER_NOTIFICATIONS_CHANNEL); + OTHER_NOTIFICATIONS_CHANNEL = null; + notificationChannel = null; + } + if (OTHER_NOTIFICATIONS_CHANNEL == null) { + if (preferences == null) { + preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + } + OTHER_NOTIFICATIONS_CHANNEL = "Other" + Utilities.random.nextLong(); + preferences.edit().putString("OtherKey", OTHER_NOTIFICATIONS_CHANNEL).commit(); + } + if (notificationChannel == null) { + notificationChannel = new NotificationChannel(OTHER_NOTIFICATIONS_CHANNEL, "Other", NotificationManager.IMPORTANCE_DEFAULT); + notificationChannel.enableLights(false); + notificationChannel.enableVibration(false); + notificationChannel.setSound(null, null); + systemNotificationManager.createNotificationChannel(notificationChannel); + } + } + public void cleanup() { popupMessages.clear(); popupReplyMessages.clear(); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - opened_dialog_id = 0; - total_unread_count = 0; - personal_count = 0; - pushMessages.clear(); - pushMessagesDict.clear(); - fcmRandomMessagesDict.clear(); - pushDialogs.clear(); - wearNotificationsIds.clear(); - lastWearNotifiedMessageId.clear(); - delayedPushMessages.clear(); - notifyCheck = false; - lastBadgeCount = 0; - try { - if (notificationDelayWakelock.isHeld()) { - notificationDelayWakelock.release(); - } - } catch (Exception e) { - FileLog.e(e); + notificationsQueue.postRunnable(() -> { + opened_dialog_id = 0; + total_unread_count = 0; + personal_count = 0; + pushMessages.clear(); + pushMessagesDict.clear(); + fcmRandomMessagesDict.clear(); + pushDialogs.clear(); + wearNotificationsIds.clear(); + lastWearNotifiedMessageId.clear(); + delayedPushMessages.clear(); + notifyCheck = false; + lastBadgeCount = 0; + try { + if (notificationDelayWakelock.isHeld()) { + notificationDelayWakelock.release(); } - setBadge(getTotalAllUnreadCount()); - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.clear(); - editor.commit(); + } catch (Exception e) { + FileLog.e(e); + } + setBadge(getTotalAllUnreadCount()); + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.commit(); - if (Build.VERSION.SDK_INT >= 26) { - try { - String keyStart = currentAccount + "channel"; - List list = systemNotificationManager.getNotificationChannels(); - int count = list.size(); - for (int a = 0; a < count; a++) { - NotificationChannel channel = list.get(a); - String id = channel.getId(); - if (id.startsWith(keyStart)) { - systemNotificationManager.deleteNotificationChannel(id); - } + if (Build.VERSION.SDK_INT >= 26) { + try { + String keyStart = currentAccount + "channel"; + List list = systemNotificationManager.getNotificationChannels(); + int count = list.size(); + for (int a = 0; a < count; a++) { + NotificationChannel channel = list.get(a); + String id = channel.getId(); + if (id.startsWith(keyStart)) { + systemNotificationManager.deleteNotificationChannel(id); } - } catch (Throwable e) { - FileLog.e(e); } + } catch (Throwable e) { + FileLog.e(e); } } }); @@ -247,23 +276,15 @@ public class NotificationsController { } public void setOpenedDialogId(final long dialog_id) { - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - opened_dialog_id = dialog_id; - } - }); + notificationsQueue.postRunnable(() -> opened_dialog_id = dialog_id); } public void setLastOnlineFromOtherDevice(final int time) { - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (BuildVars.LOGS_ENABLED) { - FileLog.d("set last online from other device = " + time); - } - lastOnlineFromOtherDevice = time; + notificationsQueue.postRunnable(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("set last online from other device = " + time); } + lastOnlineFromOtherDevice = time; }); } @@ -288,274 +309,244 @@ public class NotificationsController { } protected void forceShowPopupForReply() { - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - final ArrayList popupArray = new ArrayList<>(); - for (int a = 0; a < pushMessages.size(); a++) { - MessageObject messageObject = pushMessages.get(a); - long dialog_id = messageObject.getDialogId(); - if (messageObject.messageOwner.mentioned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || - (int) dialog_id == 0 || messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { - continue; - } - popupArray.add(0, messageObject); - } - if (!popupArray.isEmpty() && !AndroidUtilities.needShowPasscode(false)) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - popupReplyMessages = popupArray; - Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); - popupIntent.putExtra("force", true); - popupIntent.putExtra("currentAccount", currentAccount); - popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); - ApplicationLoader.applicationContext.startActivity(popupIntent); - Intent it = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - ApplicationLoader.applicationContext.sendBroadcast(it); - } - }); + notificationsQueue.postRunnable(() -> { + final ArrayList popupArray = new ArrayList<>(); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + long dialog_id = messageObject.getDialogId(); + if (messageObject.messageOwner.mentioned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || + (int) dialog_id == 0 || messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { + continue; } + popupArray.add(0, messageObject); + } + if (!popupArray.isEmpty() && !AndroidUtilities.needShowPasscode(false)) { + AndroidUtilities.runOnUIThread(() -> { + popupReplyMessages = popupArray; + Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); + popupIntent.putExtra("force", true); + popupIntent.putExtra("currentAccount", currentAccount); + popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); + ApplicationLoader.applicationContext.startActivity(popupIntent); + Intent it = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + ApplicationLoader.applicationContext.sendBroadcast(it); + }); } }); } public void removeDeletedMessagesFromNotifications(final SparseArray> deletedMessages) { final ArrayList popupArrayRemove = new ArrayList<>(0); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - int old_unread_count = total_unread_count; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - for (int a = 0; a < deletedMessages.size(); a++) { - int key = deletedMessages.keyAt(a); - long dialog_id = -key; - ArrayList mids = deletedMessages.get(key); - Integer currentCount = pushDialogs.get(dialog_id); - if (currentCount == null) { - currentCount = 0; - } - Integer newCount = currentCount; - for (int b = 0; b < mids.size(); b++) { - long mid = mids.get(b); - mid |= ((long) key) << 32; - MessageObject messageObject = pushMessagesDict.get(mid); - if (messageObject != null) { - pushMessagesDict.remove(mid); - delayedPushMessages.remove(messageObject); - pushMessages.remove(messageObject); - if (isPersonalMessage(messageObject)) { - personal_count--; - } - popupArrayRemove.add(messageObject); - newCount--; + notificationsQueue.postRunnable(() -> { + int old_unread_count = total_unread_count; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + for (int a = 0; a < deletedMessages.size(); a++) { + int key = deletedMessages.keyAt(a); + long dialog_id = -key; + ArrayList mids = deletedMessages.get(key); + Integer currentCount = pushDialogs.get(dialog_id); + if (currentCount == null) { + currentCount = 0; + } + Integer newCount = currentCount; + for (int b = 0; b < mids.size(); b++) { + long mid = mids.get(b); + mid |= ((long) key) << 32; + MessageObject messageObject = pushMessagesDict.get(mid); + if (messageObject != null) { + pushMessagesDict.remove(mid); + delayedPushMessages.remove(messageObject); + pushMessages.remove(messageObject); + if (isPersonalMessage(messageObject)) { + personal_count--; } - } - if (newCount <= 0) { - newCount = 0; - smartNotificationsDialogs.remove(dialog_id); - } - if (!newCount.equals(currentCount)) { - total_unread_count -= currentCount; - total_unread_count += newCount; - pushDialogs.put(dialog_id, newCount); - } - if (newCount == 0) { - pushDialogs.remove(dialog_id); - pushDialogsOverrideMention.remove(dialog_id); + popupArrayRemove.add(messageObject); + newCount--; } } - if (!popupArrayRemove.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { - popupMessages.remove(popupArrayRemove.get(a)); - } - } - }); + if (newCount <= 0) { + newCount = 0; + smartNotificationsDialogs.remove(dialog_id); } - if (old_unread_count != total_unread_count) { - if (!notifyCheck) { - delayedPushMessages.clear(); - showOrUpdateNotification(notifyCheck); - } else { - scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + if (!newCount.equals(currentCount)) { + total_unread_count -= currentCount; + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); + } + if (newCount == 0) { + pushDialogs.remove(dialog_id); + pushDialogsOverrideMention.remove(dialog_id); + } + } + if (!popupArrayRemove.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { + popupMessages.remove(popupArrayRemove.get(a)); } - final int pushDialogsCount = pushDialogs.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); - } - }); - } - notifyCheck = false; - if (showBadgeNumber) { - setBadge(getTotalAllUnreadCount()); + }); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); } + final int pushDialogsCount = pushDialogs.size(); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); + }); + } + notifyCheck = false; + if (showBadgeNumber) { + setBadge(getTotalAllUnreadCount()); } }); } public void removeDeletedHisoryFromNotifications(final SparseIntArray deletedMessages) { final ArrayList popupArrayRemove = new ArrayList<>(0); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - int old_unread_count = total_unread_count; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + notificationsQueue.postRunnable(() -> { + int old_unread_count = total_unread_count; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - for (int a = 0; a < deletedMessages.size(); a++) { - int key = deletedMessages.keyAt(a); - long dialog_id = -key; - int id = deletedMessages.get(key); - Integer currentCount = pushDialogs.get(dialog_id); - if (currentCount == null) { - currentCount = 0; - } - Integer newCount = currentCount; + for (int a = 0; a < deletedMessages.size(); a++) { + int key = deletedMessages.keyAt(a); + long dialog_id = -key; + int id = deletedMessages.get(key); + Integer currentCount = pushDialogs.get(dialog_id); + if (currentCount == null) { + currentCount = 0; + } + Integer newCount = currentCount; - for (int c = 0; c < pushMessages.size(); c++) { - MessageObject messageObject = pushMessages.get(c); - if (messageObject.getDialogId() == dialog_id && messageObject.getId() <= id) { - pushMessagesDict.remove(messageObject.getIdWithChannel()); - delayedPushMessages.remove(messageObject); - pushMessages.remove(messageObject); - c--; - if (isPersonalMessage(messageObject)) { - personal_count--; - } - popupArrayRemove.add(messageObject); - newCount--; + for (int c = 0; c < pushMessages.size(); c++) { + MessageObject messageObject = pushMessages.get(c); + if (messageObject.getDialogId() == dialog_id && messageObject.getId() <= id) { + pushMessagesDict.remove(messageObject.getIdWithChannel()); + delayedPushMessages.remove(messageObject); + pushMessages.remove(messageObject); + c--; + if (isPersonalMessage(messageObject)) { + personal_count--; } + popupArrayRemove.add(messageObject); + newCount--; } + } - if (newCount <= 0) { - newCount = 0; - smartNotificationsDialogs.remove(dialog_id); - } - if (!newCount.equals(currentCount)) { - total_unread_count -= currentCount; - total_unread_count += newCount; - pushDialogs.put(dialog_id, newCount); - } - if (newCount == 0) { - pushDialogs.remove(dialog_id); - pushDialogsOverrideMention.remove(dialog_id); - } + if (newCount <= 0) { + newCount = 0; + smartNotificationsDialogs.remove(dialog_id); } - if (popupArrayRemove.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { - popupMessages.remove(popupArrayRemove.get(a)); - } - } - }); + if (!newCount.equals(currentCount)) { + total_unread_count -= currentCount; + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); } - if (old_unread_count != total_unread_count) { - if (!notifyCheck) { - delayedPushMessages.clear(); - showOrUpdateNotification(notifyCheck); - } else { - scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + if (newCount == 0) { + pushDialogs.remove(dialog_id); + pushDialogsOverrideMention.remove(dialog_id); + } + } + if (popupArrayRemove.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { + popupMessages.remove(popupArrayRemove.get(a)); } - final int pushDialogsCount = pushDialogs.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); - } - }); - } - notifyCheck = false; - if (showBadgeNumber) { - setBadge(getTotalAllUnreadCount()); + }); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); } + final int pushDialogsCount = pushDialogs.size(); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); + }); + } + notifyCheck = false; + if (showBadgeNumber) { + setBadge(getTotalAllUnreadCount()); } }); } public void processReadMessages(final SparseLongArray inbox, final long dialog_id, final int max_date, final int max_id, final boolean isPopup) { final ArrayList popupArrayRemove = new ArrayList<>(0); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (inbox != null) { - for (int b = 0; b < inbox.size(); b++) { - int key = inbox.keyAt(b); - long messageId = inbox.get(key); - for (int a = 0; a < pushMessages.size(); a++) { - MessageObject messageObject = pushMessages.get(a); - if (messageObject.getDialogId() == key && messageObject.getId() <= (int) messageId) { - if (isPersonalMessage(messageObject)) { - personal_count--; - } - popupArrayRemove.add(messageObject); - long mid = messageObject.getId(); - if (messageObject.messageOwner.to_id.channel_id != 0) { - mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; - } - pushMessagesDict.remove(mid); - delayedPushMessages.remove(messageObject); - pushMessages.remove(a); - a--; + notificationsQueue.postRunnable(() -> { + if (inbox != null) { + for (int b = 0; b < inbox.size(); b++) { + int key = inbox.keyAt(b); + long messageId = inbox.get(key); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == key && messageObject.getId() <= (int) messageId) { + if (isPersonalMessage(messageObject)) { + personal_count--; } + popupArrayRemove.add(messageObject); + long mid = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + pushMessagesDict.remove(mid); + delayedPushMessages.remove(messageObject); + pushMessages.remove(a); + a--; } } } - if (dialog_id != 0 && (max_id != 0 || max_date != 0)) { - for (int a = 0; a < pushMessages.size(); a++) { - MessageObject messageObject = pushMessages.get(a); - if (messageObject.getDialogId() == dialog_id) { - boolean remove = false; - if (max_date != 0) { - if (messageObject.messageOwner.date <= max_date) { + } + if (dialog_id != 0 && (max_id != 0 || max_date != 0)) { + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == dialog_id) { + boolean remove = false; + if (max_date != 0) { + if (messageObject.messageOwner.date <= max_date) { + remove = true; + } + } else { + if (!isPopup) { + if (messageObject.getId() <= max_id || max_id < 0) { remove = true; } } else { - if (!isPopup) { - if (messageObject.getId() <= max_id || max_id < 0) { - remove = true; - } - } else { - if (messageObject.getId() == max_id || max_id < 0) { - remove = true; - } + if (messageObject.getId() == max_id || max_id < 0) { + remove = true; } } - if (remove) { - if (isPersonalMessage(messageObject)) { - personal_count--; - } - pushMessages.remove(a); - delayedPushMessages.remove(messageObject); - popupArrayRemove.add(messageObject); - long mid = messageObject.getId(); - if (messageObject.messageOwner.to_id.channel_id != 0) { - mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; - } - pushMessagesDict.remove(mid); - a--; + } + if (remove) { + if (isPersonalMessage(messageObject)) { + personal_count--; } + pushMessages.remove(a); + delayedPushMessages.remove(messageObject); + popupArrayRemove.add(messageObject); + long mid = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + pushMessagesDict.remove(mid); + a--; } } } - if (!popupArrayRemove.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { - popupMessages.remove(popupArrayRemove.get(a)); - } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); - } - }); - } + } + if (!popupArrayRemove.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0, size = popupArrayRemove.size(); a < size; a++) { + popupMessages.remove(popupArrayRemove.get(a)); + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); + }); } }); } @@ -565,178 +556,169 @@ public class NotificationsController { return; } final ArrayList popupArrayAdd = new ArrayList<>(0); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - boolean added = false; + notificationsQueue.postRunnable(() -> { + boolean added = false; - LongSparseArray settingsCache = new LongSparseArray<>(); - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - boolean allowPinned = preferences.getBoolean("PinnedMessages", true); - int popup = 0; + LongSparseArray settingsCache = new LongSparseArray<>(); + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + boolean allowPinned = preferences.getBoolean("PinnedMessages", true); + int popup = 0; - for (int a = 0; a < messageObjects.size(); a++) { - MessageObject messageObject = messageObjects.get(a); - long mid = messageObject.getId(); - long random_id = messageObject.isFcmMessage() ? messageObject.messageOwner.random_id : 0; - if (messageObject.messageOwner.to_id.channel_id != 0) { - mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; - } - MessageObject oldMessageObject = pushMessagesDict.get(mid); - if (oldMessageObject == null && messageObject.messageOwner.random_id != 0) { - oldMessageObject = fcmRandomMessagesDict.get(messageObject.messageOwner.random_id); - if (oldMessageObject != null) { - fcmRandomMessagesDict.remove(messageObject.messageOwner.random_id); - } - } + for (int a = 0; a < messageObjects.size(); a++) { + MessageObject messageObject = messageObjects.get(a); + long mid = messageObject.getId(); + long random_id = messageObject.isFcmMessage() ? messageObject.messageOwner.random_id : 0; + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + MessageObject oldMessageObject = pushMessagesDict.get(mid); + if (oldMessageObject == null && messageObject.messageOwner.random_id != 0) { + oldMessageObject = fcmRandomMessagesDict.get(messageObject.messageOwner.random_id); if (oldMessageObject != null) { - if (oldMessageObject.isFcmMessage()) { - pushMessagesDict.put(mid, messageObject); - int idxOld = pushMessages.indexOf(oldMessageObject); - if (idxOld >= 0) { - pushMessages.set(idxOld, messageObject); - } + fcmRandomMessagesDict.remove(messageObject.messageOwner.random_id); + } + } + if (oldMessageObject != null) { + if (oldMessageObject.isFcmMessage()) { + pushMessagesDict.put(mid, messageObject); + int idxOld = pushMessages.indexOf(oldMessageObject); + if (idxOld >= 0) { + pushMessages.set(idxOld, messageObject); } + } + continue; + } + long dialog_id = messageObject.getDialogId(); + long original_dialog_id = dialog_id; + if (dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { + if (!isFcm) { + playInChatSound(); + } + continue; + } + if (messageObject.messageOwner.mentioned) { + if (!allowPinned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { continue; } - long dialog_id = messageObject.getDialogId(); - long original_dialog_id = dialog_id; - if (dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { - if (!isFcm) { - playInChatSound(); - } - continue; - } - if (messageObject.messageOwner.mentioned) { - if (!allowPinned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { - continue; - } - dialog_id = messageObject.messageOwner.from_id; - } - if (isPersonalMessage(messageObject)) { - personal_count++; - } - added = true; + dialog_id = messageObject.messageOwner.from_id; + } + if (isPersonalMessage(messageObject)) { + personal_count++; + } + added = true; - int lower_id = (int) dialog_id; - boolean isChat = lower_id < 0; - int index = settingsCache.indexOfKey(dialog_id); - boolean value; - if (index >= 0) { - value = settingsCache.valueAt(index); + int lower_id = (int) dialog_id; + boolean isChat = lower_id < 0; + int index = settingsCache.indexOfKey(dialog_id); + boolean value; + if (index >= 0) { + value = settingsCache.valueAt(index); + } else { + int notifyOverride = getNotifyOverride(preferences, dialog_id); + if (notifyOverride == -1) { + value = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); } else { - int notifyOverride = getNotifyOverride(preferences, dialog_id); - if (notifyOverride == -1) { - value = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); - } else { - value = notifyOverride != 2; - } + value = notifyOverride != 2; + } - settingsCache.put(dialog_id, value); - } - if (lower_id != 0) { - if (preferences.getBoolean("custom_" + dialog_id, false)) { - popup = preferences.getInt("popup_" + dialog_id, 0); - } else { - popup = 0; - } - if (popup == 0) { - popup = preferences.getInt((int) dialog_id < 0 ? "popupGroup" : "popupAll", 0); - } else if (popup == 1) { - popup = 3; - } else if (popup == 2) { - popup = 0; - } - } - if (popup != 0 && messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { + settingsCache.put(dialog_id, value); + } + if (lower_id != 0) { + if (preferences.getBoolean("custom_" + dialog_id, false)) { + popup = preferences.getInt("popup_" + dialog_id, 0); + } else { popup = 0; } - if (value) { - if (popup != 0) { - popupArrayAdd.add(0, messageObject); - } - delayedPushMessages.add(messageObject); - pushMessages.add(0, messageObject); - if (mid != 0) { - pushMessagesDict.put(mid, messageObject); - } else if (random_id != 0) { - fcmRandomMessagesDict.put(random_id, messageObject); - } - if (original_dialog_id != dialog_id) { - pushDialogsOverrideMention.put(original_dialog_id, 1); - } + if (popup == 0) { + popup = preferences.getInt((int) dialog_id < 0 ? "popupGroup" : "popupAll", 0); + } else if (popup == 1) { + popup = 3; + } else if (popup == 2) { + popup = 0; } } + if (popup != 0 && messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { + popup = 0; + } + if (value) { + if (popup != 0) { + popupArrayAdd.add(0, messageObject); + } + delayedPushMessages.add(messageObject); + pushMessages.add(0, messageObject); + if (mid != 0) { + pushMessagesDict.put(mid, messageObject); + } else if (random_id != 0) { + fcmRandomMessagesDict.put(random_id, messageObject); + } + if (original_dialog_id != dialog_id) { + pushDialogsOverrideMention.put(original_dialog_id, 1); + } + } + } - if (added) { - notifyCheck = isLast; + if (added) { + notifyCheck = isLast; + } + + if (!popupArrayAdd.isEmpty() && !AndroidUtilities.needShowPasscode(false)) { + final int popupFinal = popup; + AndroidUtilities.runOnUIThread(() -> { + popupMessages.addAll(0, popupArrayAdd); + if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn && !SharedConfig.isWaitingForPasscodeEnter) { + if (popupFinal == 3 || popupFinal == 1 && ApplicationLoader.isScreenOn || popupFinal == 2 && !ApplicationLoader.isScreenOn) { + Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); + popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); + ApplicationLoader.applicationContext.startActivity(popupIntent); + } + } + }); + } + if (added && isFcm) { + long dialog_id = messageObjects.get(0).getDialogId(); + int old_unread_count = total_unread_count; + + int notifyOverride = getNotifyOverride(preferences, dialog_id); + if (notifyCheck) { + Integer override = pushDialogsOverrideMention.get(dialog_id); + if (override != null && override == 1) { + pushDialogsOverrideMention.put(dialog_id, 0); + notifyOverride = 1; + } + } + boolean canAddValue; + if (notifyOverride == -1) { + canAddValue = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); + } else { + canAddValue = notifyOverride != 2; } - if (!popupArrayAdd.isEmpty() && !AndroidUtilities.needShowPasscode(false)) { - final int popupFinal = popup; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - popupMessages.addAll(0, popupArrayAdd); - if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn && !SharedConfig.isWaitingForPasscodeEnter) { - if (popupFinal == 3 || popupFinal == 1 && ApplicationLoader.isScreenOn || popupFinal == 2 && !ApplicationLoader.isScreenOn) { - Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); - popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); - ApplicationLoader.applicationContext.startActivity(popupIntent); - } - } - } + Integer currentCount = pushDialogs.get(dialog_id); + Integer newCount = currentCount != null ? currentCount + 1 : 1; + + if (canAddValue) { + if (currentCount != null) { + total_unread_count -= currentCount; + } + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + } + final int pushDialogsCount = pushDialogs.size(); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); }); } - if (added && isFcm) { - long dialog_id = messageObjects.get(0).getDialogId(); - int old_unread_count = total_unread_count; - - int notifyOverride = getNotifyOverride(preferences, dialog_id); - if (notifyCheck) { - Integer override = pushDialogsOverrideMention.get(dialog_id); - if (override != null && override == 1) { - pushDialogsOverrideMention.put(dialog_id, 0); - notifyOverride = 1; - } - } - boolean canAddValue; - if (notifyOverride == -1) { - canAddValue = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); - } else { - canAddValue = notifyOverride != 2; - } - - Integer currentCount = pushDialogs.get(dialog_id); - Integer newCount = currentCount != null ? currentCount + 1 : 1; - - if (canAddValue) { - if (currentCount != null) { - total_unread_count -= currentCount; - } - total_unread_count += newCount; - pushDialogs.put(dialog_id, newCount); - } - if (old_unread_count != total_unread_count) { - if (!notifyCheck) { - delayedPushMessages.clear(); - showOrUpdateNotification(notifyCheck); - } else { - scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); - } - final int pushDialogsCount = pushDialogs.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); - } - }); - } - notifyCheck = false; - if (showBadgeNumber) { - setBadge(getTotalAllUnreadCount()); - } + notifyCheck = false; + if (showBadgeNumber) { + setBadge(getTotalAllUnreadCount()); } } }); @@ -748,101 +730,92 @@ public class NotificationsController { public void processDialogsUpdateRead(final LongSparseArray dialogsToUpdate) { final ArrayList popupArrayToRemove = new ArrayList<>(); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - int old_unread_count = total_unread_count; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - for (int b = 0; b < dialogsToUpdate.size(); b++) { - long dialog_id = dialogsToUpdate.keyAt(b); + notificationsQueue.postRunnable(() -> { + int old_unread_count = total_unread_count; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + for (int b = 0; b < dialogsToUpdate.size(); b++) { + long dialog_id = dialogsToUpdate.keyAt(b); - int notifyOverride = getNotifyOverride(preferences, dialog_id); - if (notifyCheck) { - Integer override = pushDialogsOverrideMention.get(dialog_id); - if (override != null && override == 1) { - pushDialogsOverrideMention.put(dialog_id, 0); - notifyOverride = 1; - } - } - boolean canAddValue; - if (notifyOverride == -1) { - canAddValue = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); - } else { - canAddValue = notifyOverride != 2; + int notifyOverride = getNotifyOverride(preferences, dialog_id); + if (notifyCheck) { + Integer override = pushDialogsOverrideMention.get(dialog_id); + if (override != null && override == 1) { + pushDialogsOverrideMention.put(dialog_id, 0); + notifyOverride = 1; } + } + boolean canAddValue; + if (notifyOverride == -1) { + canAddValue = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); + } else { + canAddValue = notifyOverride != 2; + } - Integer currentCount = pushDialogs.get(dialog_id); - Integer newCount = dialogsToUpdate.get(dialog_id); - if (newCount == 0) { - smartNotificationsDialogs.remove(dialog_id); - } + Integer currentCount = pushDialogs.get(dialog_id); + Integer newCount = dialogsToUpdate.get(dialog_id); + if (newCount == 0) { + smartNotificationsDialogs.remove(dialog_id); + } - if (newCount < 0) { - if (currentCount == null) { - continue; - } - newCount = currentCount + newCount; + if (newCount < 0) { + if (currentCount == null) { + continue; } - if (canAddValue || newCount == 0) { - if (currentCount != null) { - total_unread_count -= currentCount; - } + newCount = currentCount + newCount; + } + if (canAddValue || newCount == 0) { + if (currentCount != null) { + total_unread_count -= currentCount; } - if (newCount == 0) { - pushDialogs.remove(dialog_id); - pushDialogsOverrideMention.remove(dialog_id); - for (int a = 0; a < pushMessages.size(); a++) { - MessageObject messageObject = pushMessages.get(a); - if (messageObject.getDialogId() == dialog_id) { - if (isPersonalMessage(messageObject)) { - personal_count--; - } - pushMessages.remove(a); - a--; - delayedPushMessages.remove(messageObject); - long mid = messageObject.getId(); - if (messageObject.messageOwner.to_id.channel_id != 0) { - mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; - } - pushMessagesDict.remove(mid); - popupArrayToRemove.add(messageObject); + } + if (newCount == 0) { + pushDialogs.remove(dialog_id); + pushDialogsOverrideMention.remove(dialog_id); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == dialog_id) { + if (isPersonalMessage(messageObject)) { + personal_count--; } - } - } else if (canAddValue) { - total_unread_count += newCount; - pushDialogs.put(dialog_id, newCount); - } - } - if (!popupArrayToRemove.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0, size = popupArrayToRemove.size(); a < size; a++) { - popupMessages.remove(popupArrayToRemove.get(a)); + pushMessages.remove(a); + a--; + delayedPushMessages.remove(messageObject); + long mid = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; } + pushMessagesDict.remove(mid); + popupArrayToRemove.add(messageObject); } - }); - } - if (old_unread_count != total_unread_count) { - if (!notifyCheck) { - delayedPushMessages.clear(); - showOrUpdateNotification(notifyCheck); - } else { - scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); } - final int pushDialogsCount = pushDialogs.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); - } - }); + } else if (canAddValue) { + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); } - notifyCheck = false; - if (showBadgeNumber) { - setBadge(getTotalAllUnreadCount()); + } + if (!popupArrayToRemove.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0, size = popupArrayToRemove.size(); a < size; a++) { + popupMessages.remove(popupArrayToRemove.get(a)); + } + }); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance(currentAccount).getCurrentTime()); } + final int pushDialogsCount = pushDialogs.size(); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); + }); + } + notifyCheck = false; + if (showBadgeNumber) { + setBadge(getTotalAllUnreadCount()); } }); } @@ -852,72 +825,40 @@ public class NotificationsController { MessagesController.getInstance(currentAccount).putChats(chats, true); MessagesController.getInstance(currentAccount).putEncryptedChats(encryptedChats, true); - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - pushDialogs.clear(); - pushMessages.clear(); - pushMessagesDict.clear(); - total_unread_count = 0; - personal_count = 0; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - LongSparseArray settingsCache = new LongSparseArray<>(); + notificationsQueue.postRunnable(() -> { + pushDialogs.clear(); + pushMessages.clear(); + pushMessagesDict.clear(); + total_unread_count = 0; + personal_count = 0; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + LongSparseArray settingsCache = new LongSparseArray<>(); - if (messages != null) { - for (int a = 0; a < messages.size(); a++) { - TLRPC.Message message = messages.get(a); - long mid = message.id; - if (message.to_id.channel_id != 0) { - mid |= ((long) message.to_id.channel_id) << 32; - } - if (pushMessagesDict.indexOfKey(mid) >= 0) { - continue; - } - MessageObject messageObject = new MessageObject(currentAccount, message, false); - if (isPersonalMessage(messageObject)) { - personal_count++; - } - long dialog_id = messageObject.getDialogId(); - long original_dialog_id = dialog_id; - if (messageObject.messageOwner.mentioned) { - dialog_id = messageObject.messageOwner.from_id; - } - int index = settingsCache.indexOfKey(dialog_id); - boolean value; - if (index >= 0) { - value = settingsCache.valueAt(index); - } else { - int notifyOverride = getNotifyOverride(preferences, dialog_id); - if (notifyOverride == -1) { - value = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); - } else { - value = notifyOverride != 2; - } - settingsCache.put(dialog_id, value); - } - if (!value || dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { - continue; - } - pushMessagesDict.put(mid, messageObject); - pushMessages.add(0, messageObject); - if (original_dialog_id != dialog_id) { - pushDialogsOverrideMention.put(original_dialog_id, 1); - } + if (messages != null) { + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + long mid = message.id; + if (message.to_id.channel_id != 0) { + mid |= ((long) message.to_id.channel_id) << 32; + } + if (pushMessagesDict.indexOfKey(mid) >= 0) { + continue; + } + MessageObject messageObject = new MessageObject(currentAccount, message, false); + if (isPersonalMessage(messageObject)) { + personal_count++; + } + long dialog_id = messageObject.getDialogId(); + long original_dialog_id = dialog_id; + if (messageObject.messageOwner.mentioned) { + dialog_id = messageObject.messageOwner.from_id; } - } - for (int a = 0; a < dialogs.size(); a++) { - long dialog_id = dialogs.keyAt(a); int index = settingsCache.indexOfKey(dialog_id); boolean value; if (index >= 0) { value = settingsCache.valueAt(index); } else { int notifyOverride = getNotifyOverride(preferences, dialog_id); - Integer override = pushDialogsOverrideMention.get(dialog_id); - if (override != null && override == 1) { - pushDialogsOverrideMention.put(dialog_id, 0); - notifyOverride = 1; - } if (notifyOverride == -1) { value = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); } else { @@ -925,31 +866,57 @@ public class NotificationsController { } settingsCache.put(dialog_id, value); } - if (!value) { + if (!value || dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { continue; } - int count = dialogs.valueAt(a); - pushDialogs.put(dialog_id, count); - total_unread_count += count; - } - final int pushDialogsCount = pushDialogs.size(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (total_unread_count == 0) { - popupMessages.clear(); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); - } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); + pushMessagesDict.put(mid, messageObject); + pushMessages.add(0, messageObject); + if (original_dialog_id != dialog_id) { + pushDialogsOverrideMention.put(original_dialog_id, 1); } - }); - showOrUpdateNotification(SystemClock.elapsedRealtime() / 1000 < 60); - - if (showBadgeNumber) { - setBadge(getTotalAllUnreadCount()); } } + for (int a = 0; a < dialogs.size(); a++) { + long dialog_id = dialogs.keyAt(a); + int index = settingsCache.indexOfKey(dialog_id); + boolean value; + if (index >= 0) { + value = settingsCache.valueAt(index); + } else { + int notifyOverride = getNotifyOverride(preferences, dialog_id); + Integer override = pushDialogsOverrideMention.get(dialog_id); + if (override != null && override == 1) { + pushDialogsOverrideMention.put(dialog_id, 0); + notifyOverride = 1; + } + if (notifyOverride == -1) { + value = (int) dialog_id < 0 ? preferences.getBoolean("EnableGroup", true) : preferences.getBoolean("EnableAll", true); + } else { + value = notifyOverride != 2; + } + settingsCache.put(dialog_id, value); + } + if (!value) { + continue; + } + int count = dialogs.valueAt(a); + pushDialogs.put(dialog_id, count); + total_unread_count += count; + } + final int pushDialogsCount = pushDialogs.size(); + AndroidUtilities.runOnUIThread(() -> { + if (total_unread_count == 0) { + popupMessages.clear(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.notificationsCountUpdated, currentAccount); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsUnreadCounterChanged, pushDialogsCount); + }); + showOrUpdateNotification(SystemClock.elapsedRealtime() / 1000 < 60); + + if (showBadgeNumber) { + setBadge(getTotalAllUnreadCount()); + } }); } @@ -968,12 +935,7 @@ public class NotificationsController { public void setBadgeEnabled(boolean enabled) { showBadgeNumber = enabled; - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - setBadge(getTotalAllUnreadCount()); - } - }); + notificationsQueue.postRunnable(() -> setBadge(getTotalAllUnreadCount())); } private void setBadge(final int count) { @@ -1915,12 +1877,7 @@ public class NotificationsController { notificationManager.cancel(wearNotificationsIds.valueAt(a)); } wearNotificationsIds.clear(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.pushMessagesUpdated)); if (WearDataLayerListenerService.isWatchConnected()) { try { JSONObject o = new JSONObject(); @@ -1935,43 +1892,6 @@ public class NotificationsController { } } - /*public void playRecordSound() { - try { - if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { - return; - } - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (soundPool == null) { - soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); - soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { - @Override - public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { - if (status == 0) { - soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); - } - } - }); - } - if (soundRecord == 0 && !soundRecordLoaded) { - soundRecordLoaded = true; - soundRecord = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_record, 1); - } - if (soundRecord != 0) { - soundPool.play(soundRecord, 1.0f, 1.0f, 1, 0, 1.0f); - } - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } catch (Exception e) { - FileLog.e(e); - } - }*/ - private void playInChatSound() { if (!inChatSoundEnabled || MediaController.getInstance().isRecordingAudio()) { return; @@ -1990,42 +1910,36 @@ public class NotificationsController { if (notifyOverride == 2) { return; } - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (Math.abs(System.currentTimeMillis() - lastSoundPlay) <= 500) { - return; - } - try { - if (soundPool == null) { - soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); - soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { - @Override - public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { - if (status == 0) { - try { - soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); - } catch (Exception e) { - FileLog.e(e); - } - } + notificationsQueue.postRunnable(() -> { + if (Math.abs(System.currentTimeMillis() - lastSoundPlay) <= 500) { + return; + } + try { + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> { + if (status == 0) { + try { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } catch (Exception e) { + FileLog.e(e); } - }); - } - if (soundIn == 0 && !soundInLoaded) { - soundInLoaded = true; - soundIn = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_in, 1); - } - if (soundIn != 0) { - try { - soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f); - } catch (Exception e) { - FileLog.e(e); } - } - } catch (Exception e) { - FileLog.e(e); + }); } + if (soundIn == 0 && !soundInLoaded) { + soundInLoaded = true; + soundIn = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_in, 1); + } + if (soundIn != 0) { + try { + soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f); + } catch (Exception e) { + FileLog.e(e); + } + } + } catch (Exception e) { + FileLog.e(e); } }); } catch (Exception e) { @@ -2048,16 +1962,13 @@ public class NotificationsController { } protected void repeatNotificationMaybe() { - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); - if (hour >= 11 && hour <= 22) { - notificationManager.cancel(notificationId); - showOrUpdateNotification(true); - } else { - scheduleNotificationRepeat(); - } + notificationsQueue.postRunnable(() -> { + int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + if (hour >= 11 && hour <= 22) { + notificationManager.cancel(notificationId); + showOrUpdateNotification(true); + } else { + scheduleNotificationRepeat(); } }); } @@ -2433,7 +2344,7 @@ public class NotificationsController { if (AndroidUtilities.needShowPasscode(false) || SharedConfig.isWaitingForPasscodeEnter) { photoPath = null; } else { - if (pushDialogs.size() == 1) { + if (pushDialogs.size() == 1 && Build.VERSION.SDK_INT < 28) { if (chat != null) { if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) { photoPath = chat.photo.photo_small; @@ -2714,6 +2625,9 @@ public class NotificationsController { Notification mainNotification = notificationBuilder.build(); if (Build.VERSION.SDK_INT < 18) { notificationManager.notify(notificationId, mainNotification); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("show summary notification by SDK check"); + } return; } @@ -2745,6 +2659,9 @@ public class NotificationsController { } void call() { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("show dialog notification with id " + id); + } notificationManager.notify(id, notification); } } @@ -2755,6 +2672,11 @@ public class NotificationsController { serializedNotifications = new JSONArray(); } + boolean useSummaryNotification = Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1 || Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1 && sortedDialogs.size() > 1; + if (useSummaryNotification && Build.VERSION.SDK_INT >= 26) { + checkOtherNotificationsChannel(); + } + for (int b = 0, size = sortedDialogs.size(); b < size; b++) { long dialog_id = sortedDialogs.get(b); ArrayList messageObjects = messagesByDialogs.get(dialog_id); @@ -2790,15 +2712,22 @@ public class NotificationsController { boolean isSupergroup = false; String name; TLRPC.FileLocation photoPath = null; + Bitmap avatarBitmap = null; + File avatalFile = null; boolean canReply; + LongSparseArray personCache = new LongSparseArray<>(); + if (lowerId != 0) { - canReply = true; + canReply = lowerId != 777000; if (lowerId > 0) { user = MessagesController.getInstance(currentAccount).getUser(lowerId); if (user == null) { if (lastMessageObject.isFcmMessage()) { name = lastMessageObject.localName; } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("not found user to show dialog notification " + lowerId); + } continue; } } else { @@ -2815,6 +2744,9 @@ public class NotificationsController { name = lastMessageObject.localName; isChannel = lastMessageObject.localChannel; } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("not found chat to show dialog notification " + lowerId); + } continue; } } else { @@ -2831,10 +2763,16 @@ public class NotificationsController { if (dialog_id != globalSecretChatId) { TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(highId); if (encryptedChat == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("not found secret chat to show dialog notification " + highId); + } continue; } user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); if (user == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("not found secret chat user to show dialog notification " + encryptedChat.user_id); + } continue; } } @@ -2849,6 +2787,25 @@ public class NotificationsController { canReply = false; } + if (photoPath != null) { + avatalFile = FileLoader.getPathToAttach(photoPath, true); + BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(photoPath, null, "50_50"); + if (img != null) { + avatarBitmap = img.getBitmap(); + } else if (Build.VERSION.SDK_INT < 28) { + try { + if (avatalFile.exists()) { + float scaleFactor = 160.0f / AndroidUtilities.dp(50); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = scaleFactor < 1 ? 1 : (int) scaleFactor; + avatarBitmap = BitmapFactory.decodeFile(avatalFile.getAbsolutePath(), options); + } + } catch (Throwable ignore) { + + } + } + } + NotificationCompat.CarExtender.UnreadConversation.Builder unreadConvBuilder = new NotificationCompat.CarExtender.UnreadConversation.Builder(name).setLatestTimestamp((long) max_date * 1000); Intent msgHeardIntent = new Intent(ApplicationLoader.applicationContext, AutoMessageHeardReceiver.class); @@ -2892,7 +2849,13 @@ public class NotificationsController { if (count == null) { count = 0; } - NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("").setConversationTitle(String.format("%1$s (%2$s)", name, LocaleController.formatPluralString("NewMessages", Math.max(count, messageObjects.size())))); + String conversationName = String.format("%1$s (%2$s)", name, LocaleController.formatPluralString("NewMessages", Math.max(count, messageObjects.size()))); + + NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(""); + messagingStyle.setConversationTitle(conversationName); + if (!isChannel && lowerId < 0) { + messagingStyle.setGroupConversation(true); + } StringBuilder text = new StringBuilder(); String senderName[] = new String[1]; @@ -2906,6 +2869,9 @@ public class NotificationsController { MessageObject messageObject = messageObjects.get(a); String message = getShortStringForMessage(messageObject, senderName); if (message == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.w("message text is null for " + messageObject.getId() + " did = " + messageObject.getDialogId()); + } continue; } if (text.length() > 0) { @@ -2918,7 +2884,64 @@ public class NotificationsController { } unreadConvBuilder.addMessage(message); - messagingStyle.addMessage(message, ((long) messageObject.messageOwner.date) * 1000, senderName[0] == null ? "" : senderName[0]); + + long uid; + if (lowerId > 0) { + uid = lowerId; + } else if (isChannel) { + uid = -lowerId; + } else if (lowerId < 0) { + uid = messageObject.getFromId(); + } else { + uid = dialog_id; + } + Person person = personCache.get(uid); + if (person == null) { + Person.Builder personBuilder = new Person.Builder().setName(senderName[0] == null ? "" : senderName[0]); + if (Build.VERSION.SDK_INT >= 28) { + File avatar = null; + if (lowerId > 0 || isChannel) { + avatar = avatalFile; + } else if (lowerId < 0) { + int fromId = messageObject.getFromId(); + TLRPC.User sender = MessagesController.getInstance(currentAccount).getUser(fromId); + if (sender == null) { + sender = MessagesStorage.getInstance(currentAccount).getUserSync(fromId); + if (sender != null) { + MessagesController.getInstance(currentAccount).putUser(sender, true); + } + } + if (sender != null && sender.photo != null && sender.photo.photo_small != null && sender.photo.photo_small.volume_id != 0 && sender.photo.photo_small.local_id != 0) { + avatar = FileLoader.getPathToAttach(sender.photo.photo_small, true); + } + } + if (avatar != null) { + try { + Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(avatar), (decoder, info, src) -> decoder.setPostProcessor((canvas) -> { + Path path = new Path(); + path.setFillType(Path.FillType.INVERSE_EVEN_ODD); + int width = canvas.getWidth(); + int height = canvas.getHeight(); + path.addRoundRect(0, 0, width, height, width / 2, width / 2, Path.Direction.CW); + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setColor(Color.TRANSPARENT); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); + canvas.drawPath(path, paint); + return PixelFormat.TRANSLUCENT; + })); + IconCompat icon = IconCompat.createWithBitmap(bitmap); + personBuilder.setIcon(icon); + } catch (Throwable ignore) { + + } + } + } + person = personBuilder.build(); + personCache.put(uid, person); + } + + messagingStyle.addMessage(message, ((long) messageObject.messageOwner.date) * 1000, person); if (messageObject.isVoice()) { List messages = messagingStyle.getMessages(); if (!messages.isEmpty()) { @@ -2983,7 +3006,7 @@ public class NotificationsController { wearableExtender.addAction(wearReplyAction); } PendingIntent readPendingIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, internalId, msgHeardIntent, PendingIntent.FLAG_UPDATE_CURRENT); - NotificationCompat.Action readAction = new NotificationCompat.Action.Builder(R.drawable.menu_read, LocaleController.getString("MarkAsRead", R.string.MarkAsRead).toUpperCase(), readPendingIntent).build(); + NotificationCompat.Action readAction = new NotificationCompat.Action.Builder(R.drawable.menu_read, LocaleController.getString("MarkAsRead", R.string.MarkAsRead), readPendingIntent).build(); String dismissalID; if (lowerId != 0) { @@ -3011,7 +3034,6 @@ public class NotificationsController { NotificationCompat.Builder builder = new NotificationCompat.Builder(ApplicationLoader.applicationContext) .setContentTitle(name) .setSmallIcon(R.drawable.notification) - .setGroup(notificationGroup) .setContentText(text.toString()) .setAutoCancel(true) .setNumber(messageObjects.size()) @@ -3020,7 +3042,6 @@ public class NotificationsController { .setWhen(date) .setShowWhen(true) .setShortcutId("sdid_" + dialog_id) - .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) .setStyle(messagingStyle) .setContentIntent(contentIntent) .extend(wearableExtender) @@ -3028,6 +3049,11 @@ public class NotificationsController { .extend(new NotificationCompat.CarExtender().setUnreadConversation(unreadConvBuilder.build())) .setCategory(NotificationCompat.CATEGORY_MESSAGE); + if (useSummaryNotification) { + builder.setGroup(notificationGroup); + builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY); + } + if (wearReplyAction != null) { builder.addAction(wearReplyAction); } @@ -3038,26 +3064,8 @@ public class NotificationsController { if (lowerId == 0) { builder.setLocalOnly(true); } - if (photoPath != null) { - BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(photoPath, null, "50_50"); - if (img != null) { - builder.setLargeIcon(img.getBitmap()); - } else { - try { - File file = FileLoader.getPathToAttach(photoPath, true); - if (file.exists()) { - float scaleFactor = 160.0f / AndroidUtilities.dp(50); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = scaleFactor < 1 ? 1 : (int) scaleFactor; - Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options); - if (bitmap != null) { - builder.setLargeIcon(bitmap); - } - } - } catch (Throwable e) { - //ignore - } - } + if (avatarBitmap != null && Build.VERSION.SDK_INT < 28) { + builder.setLargeIcon(avatarBitmap); } if (!AndroidUtilities.needShowPasscode(false) && !SharedConfig.isWaitingForPasscodeEnter && rows != null) { @@ -3084,7 +3092,11 @@ public class NotificationsController { } if (Build.VERSION.SDK_INT >= 26) { - builder.setChannelId(OTHER_NOTIFICATIONS_CHANNEL); + if (useSummaryNotification) { + builder.setChannelId(OTHER_NOTIFICATIONS_CHANNEL); + } else { + builder.setChannelId(mainNotification.getChannelId()); + } } holders.add(new NotificationHolder(internalId, builder.build())); wearNotificationsIds.put(dialog_id, internalId); @@ -3119,13 +3131,24 @@ public class NotificationsController { } } - notificationManager.notify(notificationId, mainNotification); + if (useSummaryNotification) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("show summary with id " + notificationId); + } + notificationManager.notify(notificationId, mainNotification); + } else { + notificationManager.cancel(notificationId); + } for (int a = 0, size = holders.size(); a < size; a++) { holders.get(a).call(); } for (int a = 0; a < oldIdsWear.size(); a++) { - notificationManager.cancel(oldIdsWear.valueAt(a)); + Integer id = oldIdsWear.valueAt(a); + if (BuildVars.LOGS_ENABLED) { + FileLog.w("cancel notification id " + id); + } + notificationManager.cancel(id); } if (serializedNotifications != null) { try { @@ -3149,43 +3172,37 @@ public class NotificationsController { } catch (Exception e) { FileLog.e(e); } - notificationsQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - if (Math.abs(System.currentTimeMillis() - lastSoundOutPlay) <= 100) { - return; - } - lastSoundOutPlay = System.currentTimeMillis(); - if (soundPool == null) { - soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); - soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { - @Override - public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { - if (status == 0) { - try { - soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); - } catch (Exception e) { - FileLog.e(e); - } - } - } - }); - } - if (soundOut == 0 && !soundOutLoaded) { - soundOutLoaded = true; - soundOut = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_out, 1); - } - if (soundOut != 0) { - try { - soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f); - } catch (Exception e) { - FileLog.e(e); - } - } - } catch (Exception e) { - FileLog.e(e); + notificationsQueue.postRunnable(() -> { + try { + if (Math.abs(System.currentTimeMillis() - lastSoundOutPlay) <= 100) { + return; } + lastSoundOutPlay = System.currentTimeMillis(); + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> { + if (status == 0) { + try { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } catch (Exception e) { + FileLog.e(e); + } + } + }); + } + if (soundOut == 0 && !soundOutLoaded) { + soundOutLoaded = true; + soundOut = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_out, 1); + } + if (soundOut != 0) { + try { + soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f); + } catch (Exception e) { + FileLog.e(e); + } + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -3217,11 +3234,8 @@ public class NotificationsController { req.peer = new TLRPC.TL_inputNotifyPeer(); ((TLRPC.TL_inputNotifyPeer) req.peer).peer = MessagesController.getInstance(currentAccount).getInputPeer((int) dialog_id); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SRPHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SRPHelper.java new file mode 100644 index 000000000..1605397f7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SRPHelper.java @@ -0,0 +1,107 @@ +package org.telegram.messenger; + +import org.telegram.tgnet.TLRPC; + +import java.math.BigInteger; + +public class SRPHelper { + + public static byte[] getBigIntegerBytes(BigInteger value) { + byte[] bytes = value.toByteArray(); + if (bytes.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(bytes, 1, correctedAuth, 0, 256); + return correctedAuth; + } else if (bytes.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(bytes, 0, correctedAuth, 256 - bytes.length, bytes.length); + for (int a = 0; a < 256 - bytes.length; a++) { + correctedAuth[a] = 0; + } + return correctedAuth; + } + return bytes; + } + + public static byte[] getX(byte[] passwordBytes, TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo) { + byte[] x_bytes = Utilities.computeSHA256(algo.salt1, passwordBytes, algo.salt1); + x_bytes = Utilities.computeSHA256(algo.salt2, x_bytes, algo.salt2); + x_bytes = Utilities.computePBKDF2(x_bytes, algo.salt1); + return Utilities.computeSHA256(algo.salt2, x_bytes, algo.salt2); + } + + public static BigInteger getV(byte[] passwordBytes, TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo) { + BigInteger g = BigInteger.valueOf(algo.g); + byte[] g_bytes = getBigIntegerBytes(g); + BigInteger p = new BigInteger(1, algo.p); + + byte[] x_bytes = getX(passwordBytes, algo); + BigInteger x = new BigInteger(1, x_bytes); + return g.modPow(x, p); + } + + public static byte[] getVBytes(byte[] passwordBytes, TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo) { + if (!Utilities.isGoodPrime(algo.p, algo.g)) { + return null; + } + return getBigIntegerBytes(getV(passwordBytes, algo)); + } + + public static TLRPC.TL_inputCheckPasswordSRP startCheck(byte[] x_bytes, long srp_id, byte[] srp_B, TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo) { + if (x_bytes == null || srp_B == null || srp_B.length == 0 || !Utilities.isGoodPrime(algo.p, algo.g)) { + return null; + } + BigInteger g = BigInteger.valueOf(algo.g); + byte[] g_bytes = getBigIntegerBytes(g); + BigInteger p = new BigInteger(1, algo.p); + + byte[] k_bytes = Utilities.computeSHA256(algo.p, g_bytes); + BigInteger k = new BigInteger(1, k_bytes); + + BigInteger x = new BigInteger(1, x_bytes); + + byte[] a_bytes = new byte[256]; + Utilities.random.nextBytes(a_bytes); + BigInteger a = new BigInteger(1, a_bytes); + + BigInteger A = g.modPow(a, p); + byte[] A_bytes = getBigIntegerBytes(A); + + BigInteger B = new BigInteger(1, srp_B); + if (B.compareTo(BigInteger.ZERO) <= 0 || B.compareTo(p) >= 0) { + return null; + } + byte[] B_bytes = getBigIntegerBytes(B); + + byte[] u_bytes = Utilities.computeSHA256(A_bytes, B_bytes); + BigInteger u = new BigInteger(1, u_bytes); + if (u.compareTo(BigInteger.ZERO) == 0) { + return null; + } + + BigInteger B_kgx = B.subtract(k.multiply(g.modPow(x, p)).mod(p)); + if (B_kgx.compareTo(BigInteger.ZERO) < 0) { + B_kgx = B_kgx.add(p); + } + if (!Utilities.isGoodGaAndGb(B_kgx, p)) { + return null; + } + + BigInteger S = B_kgx.modPow(a.add(u.multiply(x)), p); + byte[] S_bytes = getBigIntegerBytes(S); + + byte[] K_bytes = Utilities.computeSHA256(S_bytes); + + byte[] p_hash = Utilities.computeSHA256(algo.p); + byte[] g_hash = Utilities.computeSHA256(g_bytes); + for (int i = 0; i < p_hash.length; i++) { + p_hash[i] = (byte) (g_hash[i] ^ p_hash[i]); + } + + TLRPC.TL_inputCheckPasswordSRP result = new TLRPC.TL_inputCheckPasswordSRP(); + result.M1 = Utilities.computeSHA256(p_hash, Utilities.computeSHA256(algo.salt1), Utilities.computeSHA256(algo.salt2), A_bytes, B_bytes, K_bytes); + result.A = A_bytes; + result.srp_id = srp_id; + return result; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java index ce99c3289..c3632d59e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -18,7 +18,6 @@ import org.telegram.SQLite.SQLiteCursor; import org.telegram.tgnet.AbstractSerializedData; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLClassStore; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -28,7 +27,6 @@ import java.io.File; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; @@ -108,14 +106,11 @@ public class SecretChatHelper { protected void processPendingEncMessages() { if (!pendingEncMessagesToDelete.isEmpty()) { final ArrayList pendingEncMessagesToDeleteCopy = new ArrayList<>(pendingEncMessagesToDelete); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < pendingEncMessagesToDeleteCopy.size(); a++) { - MessageObject messageObject = MessagesController.getInstance(currentAccount).dialogMessagesByRandomIds.get(pendingEncMessagesToDeleteCopy.get(a)); - if (messageObject != null) { - messageObject.deleted = true; - } + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < pendingEncMessagesToDeleteCopy.size(); a++) { + MessageObject messageObject = MessagesController.getInstance(currentAccount).dialogMessagesByRandomIds.get(pendingEncMessagesToDeleteCopy.get(a)); + if (messageObject != null) { + messageObject.deleted = true; } } }); @@ -199,14 +194,11 @@ public class SecretChatHelper { dialog.top_message = 0; dialog.last_message_date = update.date; MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).dialogs_dict.put(dialog.id, dialog); - MessagesController.getInstance(currentAccount).dialogs.add(dialog); - MessagesController.getInstance(currentAccount).sortDialogs(null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).dialogs_dict.put(dialog.id, dialog); + MessagesController.getInstance(currentAccount).dialogs.add(dialog); + MessagesController.getInstance(currentAccount).sortDialogs(null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); }); MessagesStorage.getInstance(currentAccount).putEncryptedChat(newChat, user, dialog); acceptSecretChat(newChat); @@ -232,15 +224,12 @@ public class SecretChatHelper { newChat.admin_id = exist.admin_id; newChat.mtproto_seq = exist.mtproto_seq; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (exist != null) { - MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); - } - MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + AndroidUtilities.runOnUIThread(() -> { + if (exist != null) { + MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); } + MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); }); } } @@ -550,216 +539,201 @@ public class SecretChatHelper { return; } SendMessagesHelper.getInstance(currentAccount).putToSendingMessages(newMsgObj); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - try { - TLObject toEncryptObject; + Utilities.stageQueue.postRunnable(() -> { + try { + TLObject toEncryptObject; - TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); - int myLayer = Math.max(46, AndroidUtilities.getMyLayerVersion(chat.layer)); - layer.layer = Math.min(myLayer, Math.max(46, AndroidUtilities.getPeerLayerVersion(chat.layer))); - layer.message = req; - layer.random_bytes = new byte[15]; - Utilities.random.nextBytes(layer.random_bytes); - toEncryptObject = layer; + TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); + int myLayer = Math.max(46, AndroidUtilities.getMyLayerVersion(chat.layer)); + layer.layer = Math.min(myLayer, Math.max(46, AndroidUtilities.getPeerLayerVersion(chat.layer))); + layer.message = req; + layer.random_bytes = new byte[15]; + Utilities.random.nextBytes(layer.random_bytes); + toEncryptObject = layer; - int mtprotoVersion = AndroidUtilities.getPeerLayerVersion(chat.layer) >= 73 ? 2 : 1; + int mtprotoVersion = AndroidUtilities.getPeerLayerVersion(chat.layer) >= 73 ? 2 : 1; - if (chat.seq_in == 0 && chat.seq_out == 0) { - if (chat.admin_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - chat.seq_out = 1; - chat.seq_in = -2; - } else { - chat.seq_in = -1; - } - } - - if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { - layer.in_seq_no = chat.seq_in > 0 ? chat.seq_in : chat.seq_in + 2; - layer.out_seq_no = chat.seq_out; - chat.seq_out += 2; - if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { - if (chat.key_create_date == 0) { - chat.key_create_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - } - chat.key_use_count_out++; - if ((chat.key_use_count_out >= 100 || chat.key_create_date < ConnectionsManager.getInstance(currentAccount).getCurrentTime() - 60 * 60 * 24 * 7) && chat.exchange_id == 0 && chat.future_key_fingerprint == 0) { - requestNewSecretChatKey(chat); - } - } - MessagesStorage.getInstance(currentAccount).updateEncryptedChatSeq(chat, false); - if (newMsgObj != null) { - newMsgObj.seq_in = layer.in_seq_no; - newMsgObj.seq_out = layer.out_seq_no; - MessagesStorage.getInstance(currentAccount).setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); - } + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getInstance(currentAccount).getClientUserId()) { + chat.seq_out = 1; + chat.seq_in = -2; } else { - layer.in_seq_no = newMsgObj.seq_in; - layer.out_seq_no = newMsgObj.seq_out; - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d(req + " send message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + chat.seq_in = -1; } + } - int len = toEncryptObject.getObjectSize(); - NativeByteBuffer toEncrypt = new NativeByteBuffer(4 + len); - toEncrypt.writeInt32(len); - toEncryptObject.serializeToStream(toEncrypt); - - len = toEncrypt.length(); - int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; - if (mtprotoVersion == 2) { - extraLen += (2 + Utilities.random.nextInt(3)) * 16; - } - - NativeByteBuffer dataForEncryption = new NativeByteBuffer(len + extraLen); - toEncrypt.position(0); - dataForEncryption.writeBytes(toEncrypt); - if (extraLen != 0) { - byte[] b = new byte[extraLen]; - Utilities.random.nextBytes(b); - dataForEncryption.writeBytes(b); - } - - byte[] messageKey = new byte[16]; - byte[] messageKeyFull; - boolean incoming = mtprotoVersion == 2 && chat.admin_id != UserConfig.getInstance(currentAccount).getClientUserId(); - if (mtprotoVersion == 2) { - messageKeyFull = Utilities.computeSHA256(chat.auth_key, 88 + (incoming ? 8 : 0), 32, dataForEncryption.buffer, 0, dataForEncryption.buffer.limit()); - System.arraycopy(messageKeyFull, 8, messageKey, 0, 16); - } else { - messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); - System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); - } - toEncrypt.reuse(); - - MessageKeyData keyData = MessageKeyData.generateMessageKeyData(chat.auth_key, messageKey, incoming, mtprotoVersion); - - Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); - - NativeByteBuffer data = new NativeByteBuffer(8 + messageKey.length + dataForEncryption.length()); - dataForEncryption.position(0); - data.writeInt64(chat.key_fingerprint); - data.writeBytes(messageKey); - data.writeBytes(dataForEncryption); - dataForEncryption.reuse(); - data.position(0); - - TLObject reqToSend; - - if (encryptedFile == null) { - if (req instanceof TLRPC.TL_decryptedMessageService) { - TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - reqToSend = req2; - } else { - TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - reqToSend = req2; + if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { + layer.in_seq_no = chat.seq_in > 0 ? chat.seq_in : chat.seq_in + 2; + layer.out_seq_no = chat.seq_out; + chat.seq_out += 2; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { + if (chat.key_create_date == 0) { + chat.key_create_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); } - } else { - TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); + chat.key_use_count_out++; + if ((chat.key_use_count_out >= 100 || chat.key_create_date < ConnectionsManager.getInstance(currentAccount).getCurrentTime() - 60 * 60 * 24 * 7) && chat.exchange_id == 0 && chat.future_key_fingerprint == 0) { + requestNewSecretChatKey(chat); + } + } + MessagesStorage.getInstance(currentAccount).updateEncryptedChatSeq(chat, false); + if (newMsgObj != null) { + newMsgObj.seq_in = layer.in_seq_no; + newMsgObj.seq_out = layer.out_seq_no; + MessagesStorage.getInstance(currentAccount).setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); + } + } else { + layer.in_seq_no = newMsgObj.seq_in; + layer.out_seq_no = newMsgObj.seq_out; + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d(req + " send message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + } + + int len = toEncryptObject.getObjectSize(); + NativeByteBuffer toEncrypt = new NativeByteBuffer(4 + len); + toEncrypt.writeInt32(len); + toEncryptObject.serializeToStream(toEncrypt); + + len = toEncrypt.length(); + int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; + if (mtprotoVersion == 2) { + extraLen += (2 + Utilities.random.nextInt(3)) * 16; + } + + NativeByteBuffer dataForEncryption = new NativeByteBuffer(len + extraLen); + toEncrypt.position(0); + dataForEncryption.writeBytes(toEncrypt); + if (extraLen != 0) { + byte[] b = new byte[extraLen]; + Utilities.random.nextBytes(b); + dataForEncryption.writeBytes(b); + } + + byte[] messageKey = new byte[16]; + byte[] messageKeyFull; + boolean incoming = mtprotoVersion == 2 && chat.admin_id != UserConfig.getInstance(currentAccount).getClientUserId(); + if (mtprotoVersion == 2) { + messageKeyFull = Utilities.computeSHA256(chat.auth_key, 88 + (incoming ? 8 : 0), 32, dataForEncryption.buffer, 0, dataForEncryption.buffer.limit()); + System.arraycopy(messageKeyFull, 8, messageKey, 0, 16); + } else { + messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); + System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); + } + toEncrypt.reuse(); + + MessageKeyData keyData = MessageKeyData.generateMessageKeyData(chat.auth_key, messageKey, incoming, mtprotoVersion); + + Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); + + NativeByteBuffer data = new NativeByteBuffer(8 + messageKey.length + dataForEncryption.length()); + dataForEncryption.position(0); + data.writeInt64(chat.key_fingerprint); + data.writeBytes(messageKey); + data.writeBytes(dataForEncryption); + dataForEncryption.reuse(); + data.position(0); + + TLObject reqToSend; + + if (encryptedFile == null) { + if (req instanceof TLRPC.TL_decryptedMessageService) { + TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } else { + TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); req2.data = data; req2.random_id = req.random_id; req2.peer = new TLRPC.TL_inputEncryptedChat(); req2.peer.chat_id = chat.id; req2.peer.access_hash = chat.access_hash; - req2.file = encryptedFile; reqToSend = req2; } - ConnectionsManager.getInstance(currentAccount).sendRequest(reqToSend, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { - TLRPC.EncryptedChat currentChat = MessagesController.getInstance(currentAccount).getEncryptedChat(chat.id); - if (currentChat == null) { - currentChat = chat; - } - - if (currentChat.key_hash == null) { - currentChat.key_hash = AndroidUtilities.calcAuthKeyHash(currentChat.auth_key); - } - - if (AndroidUtilities.getPeerLayerVersion(currentChat.layer) >= 46 && currentChat.key_hash.length == 16) { - try { - byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); - byte[] key_hash = new byte[36]; - System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); - System.arraycopy(sha256, 0, key_hash, 16, 20); - currentChat.key_hash = key_hash; - MessagesStorage.getInstance(currentAccount).updateEncryptedChat(currentChat); - } catch (Throwable e) { - FileLog.e(e); - } - } - - sendingNotifyLayer.remove((Integer) currentChat.id); - currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); - MessagesStorage.getInstance(currentAccount).updateEncryptedChatLayer(currentChat); - } - } - if (newMsgObj != null) { - if (error == null) { - final String attachPath = newMsgObj.attachPath; - final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; - if (isSecretVisibleMessage(newMsgObj)) { - newMsgObj.date = res.date; - } - if (newMsg != null && res.file instanceof TLRPC.TL_encryptedFile) { - updateMediaPaths(newMsg, res.file, req, originalPath); - } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - if (isSecretInvisibleMessage(newMsgObj)) { - res.date = 0; - } - MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false, 0); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L); - SendMessagesHelper.getInstance(currentAccount).processSentMessage(newMsgObj.id); - if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj)) { - SendMessagesHelper.getInstance(currentAccount).stopVideoService(attachPath); - } - SendMessagesHelper.getInstance(currentAccount).removeFromSendingMessages(newMsgObj.id); - } - }); - } - }); - } else { - MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); - SendMessagesHelper.getInstance(currentAccount).processSentMessage(newMsgObj.id); - if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj)) { - SendMessagesHelper.getInstance(currentAccount).stopVideoService(newMsgObj.attachPath); - } - SendMessagesHelper.getInstance(currentAccount).removeFromSendingMessages(newMsgObj.id); - } - }); - } - } - } - }, ConnectionsManager.RequestFlagInvokeAfter); - } catch (Exception e) { - FileLog.e(e); + } else { + TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + req2.file = encryptedFile; + reqToSend = req2; } + ConnectionsManager.getInstance(currentAccount).sendRequest(reqToSend, (response, error) -> { + if (error == null) { + if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + TLRPC.EncryptedChat currentChat = MessagesController.getInstance(currentAccount).getEncryptedChat(chat.id); + if (currentChat == null) { + currentChat = chat; + } + + if (currentChat.key_hash == null) { + currentChat.key_hash = AndroidUtilities.calcAuthKeyHash(currentChat.auth_key); + } + + if (AndroidUtilities.getPeerLayerVersion(currentChat.layer) >= 46 && currentChat.key_hash.length == 16) { + try { + byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); + byte[] key_hash = new byte[36]; + System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); + System.arraycopy(sha256, 0, key_hash, 16, 20); + currentChat.key_hash = key_hash; + MessagesStorage.getInstance(currentAccount).updateEncryptedChat(currentChat); + } catch (Throwable e) { + FileLog.e(e); + } + } + + sendingNotifyLayer.remove((Integer) currentChat.id); + currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); + MessagesStorage.getInstance(currentAccount).updateEncryptedChatLayer(currentChat); + } + } + if (newMsgObj != null) { + if (error == null) { + final String attachPath = newMsgObj.attachPath; + final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; + if (isSecretVisibleMessage(newMsgObj)) { + newMsgObj.date = res.date; + } + if (newMsg != null && res.file instanceof TLRPC.TL_encryptedFile) { + updateMediaPaths(newMsg, res.file, req, originalPath); + } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + if (isSecretInvisibleMessage(newMsgObj)) { + res.date = 0; + } + MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false, 0); + AndroidUtilities.runOnUIThread(() -> { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L); + SendMessagesHelper.getInstance(currentAccount).processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance(currentAccount).stopVideoService(attachPath); + } + SendMessagesHelper.getInstance(currentAccount).removeFromSendingMessages(newMsgObj.id); + }); + }); + } else { + MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); + AndroidUtilities.runOnUIThread(() -> { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + SendMessagesHelper.getInstance(currentAccount).processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance(currentAccount).stopVideoService(newMsgObj.attachPath); + } + SendMessagesHelper.getInstance(currentAccount).removeFromSendingMessages(newMsgObj.id); + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -786,12 +760,7 @@ public class SecretChatHelper { if (currentPeerLayer < CURRENT_SECRET_CHAT_LAYER) { sendNotifyLayerMessage(chat, null); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, chat); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, chat)); } public TLRPC.Message processDecryptedObject(final TLRPC.EncryptedChat chat, final TLRPC.EncryptedFile file, int date, TLObject object, boolean new_key_used) { @@ -1087,32 +1056,21 @@ public class SecretChatHelper { return newMessage; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) { final long did = ((long) chat.id) << 32; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); - if (dialog != null) { - dialog.unread_count = 0; - MessagesController.getInstance(currentAccount).dialogMessage.remove(dialog.id); - } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationsController.getInstance(currentAccount).processReadMessages(null, did, 0, Integer.MAX_VALUE, false); - LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); - dialogsToUpdate.put(did, 0); - NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); - } - }); - } - }); - MessagesStorage.getInstance(currentAccount).deleteDialog(did, 1); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, false); + AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); + if (dialog != null) { + dialog.unread_count = 0; + MessagesController.getInstance(currentAccount).dialogMessage.remove(dialog.id); } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + NotificationsController.getInstance(currentAccount).processReadMessages(null, did, 0, Integer.MAX_VALUE, false); + LongSparseArray dialogsToUpdate = new LongSparseArray<>(1); + dialogsToUpdate.put(did, 0); + NotificationsController.getInstance(currentAccount).processDialogsUpdateRead(dialogsToUpdate); + })); + MessagesStorage.getInstance(currentAccount).deleteDialog(did, 1); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, false); }); return null; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) { @@ -1169,7 +1127,7 @@ public class SecretChatHelper { byte[] correctedAuth = new byte[256]; System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; + correctedAuth[a] = 0; } authKey = correctedAuth; } @@ -1212,7 +1170,7 @@ public class SecretChatHelper { byte[] correctedAuth = new byte[256]; System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; + correctedAuth[a] = 0; } authKey = correctedAuth; } @@ -1324,88 +1282,77 @@ public class SecretChatHelper { if (encryptedChat == null || endSeq - startSeq < 0) { return; } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - int sSeq = startSeq; - if (encryptedChat.admin_id == UserConfig.getInstance(currentAccount).getClientUserId() && sSeq % 2 == 0) { - sSeq++; - } - - SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT uid FROM requested_holes WHERE uid = %d AND ((seq_out_start >= %d AND %d <= seq_out_end) OR (seq_out_start >= %d AND %d <= seq_out_end))", encryptedChat.id, sSeq, sSeq, endSeq, endSeq)); - boolean exists = cursor.next(); - cursor.dispose(); - if (exists) { - return; - } - - long dialog_id = ((long) encryptedChat.id) << 32; - SparseArray messagesToResend = new SparseArray<>(); - final ArrayList messages = new ArrayList<>(); - for (int a = sSeq; a < endSeq; a += 2) { - messagesToResend.put(a, null); - } - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT m.data, r.random_id, s.seq_in, s.seq_out, m.ttl, s.mid FROM messages_seq as s LEFT JOIN randoms as r ON r.mid = s.mid LEFT JOIN messages as m ON m.mid = s.mid WHERE m.uid = %d AND m.out = 1 AND s.seq_out >= %d AND s.seq_out <= %d ORDER BY seq_out ASC", dialog_id, sSeq, endSeq)); - while (cursor.next()) { - TLRPC.Message message; - long random_id = cursor.longValue(1); - if (random_id == 0) { - random_id = Utilities.random.nextLong(); - } - int seq_in = cursor.intValue(2); - int seq_out = cursor.intValue(3); - int mid = cursor.intValue(5); - - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); - data.reuse(); - message.random_id = random_id; - message.dialog_id = dialog_id; - message.seq_in = seq_in; - message.seq_out = seq_out; - message.ttl = cursor.intValue(4); - } else { - message = createDeleteMessage(mid, seq_out, seq_in, random_id, encryptedChat); - } - messages.add(message); - messagesToResend.remove(seq_out); - } - cursor.dispose(); - if (messagesToResend.size() != 0) { - for (int a = 0; a < messagesToResend.size(); a++) { - messages.add(createDeleteMessage(UserConfig.getInstance(currentAccount).getNewMessageId(), messagesToResend.keyAt(a), 0, Utilities.random.nextLong(), encryptedChat)); - } - UserConfig.getInstance(currentAccount).saveConfig(false); - } - Collections.sort(messages, new Comparator() { - @Override - public int compare(TLRPC.Message lhs, TLRPC.Message rhs) { - return AndroidUtilities.compare(lhs.seq_out, rhs.seq_out); - } - }); - ArrayList encryptedChats = new ArrayList<>(); - encryptedChats.add(encryptedChat); - - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < messages.size(); a++) { - TLRPC.Message message = messages.get(a); - MessageObject messageObject = new MessageObject(currentAccount, message, false); - messageObject.resendAsIs = true; - SendMessagesHelper.getInstance(currentAccount).retrySendMessage(messageObject, true); - } - } - }); - - SendMessagesHelper.getInstance(currentAccount).processUnsentMessages(messages, new ArrayList(), new ArrayList(), encryptedChats); - MessagesStorage.getInstance(currentAccount).getDatabase().executeFast(String.format(Locale.US, "REPLACE INTO requested_holes VALUES(%d, %d, %d)", encryptedChat.id, sSeq, endSeq)).stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + int sSeq = startSeq; + if (encryptedChat.admin_id == UserConfig.getInstance(currentAccount).getClientUserId() && sSeq % 2 == 0) { + sSeq++; } + + SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT uid FROM requested_holes WHERE uid = %d AND ((seq_out_start >= %d AND %d <= seq_out_end) OR (seq_out_start >= %d AND %d <= seq_out_end))", encryptedChat.id, sSeq, sSeq, endSeq, endSeq)); + boolean exists = cursor.next(); + cursor.dispose(); + if (exists) { + return; + } + + long dialog_id = ((long) encryptedChat.id) << 32; + SparseArray messagesToResend = new SparseArray<>(); + final ArrayList messages = new ArrayList<>(); + for (int a = sSeq; a < endSeq; a += 2) { + messagesToResend.put(a, null); + } + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT m.data, r.random_id, s.seq_in, s.seq_out, m.ttl, s.mid FROM messages_seq as s LEFT JOIN randoms as r ON r.mid = s.mid LEFT JOIN messages as m ON m.mid = s.mid WHERE m.uid = %d AND m.out = 1 AND s.seq_out >= %d AND s.seq_out <= %d ORDER BY seq_out ASC", dialog_id, sSeq, endSeq)); + while (cursor.next()) { + TLRPC.Message message; + long random_id = cursor.longValue(1); + if (random_id == 0) { + random_id = Utilities.random.nextLong(); + } + int seq_in = cursor.intValue(2); + int seq_out = cursor.intValue(3); + int mid = cursor.intValue(5); + + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.readAttachPath(data, UserConfig.getInstance(currentAccount).clientUserId); + data.reuse(); + message.random_id = random_id; + message.dialog_id = dialog_id; + message.seq_in = seq_in; + message.seq_out = seq_out; + message.ttl = cursor.intValue(4); + } else { + message = createDeleteMessage(mid, seq_out, seq_in, random_id, encryptedChat); + } + messages.add(message); + messagesToResend.remove(seq_out); + } + cursor.dispose(); + if (messagesToResend.size() != 0) { + for (int a = 0; a < messagesToResend.size(); a++) { + messages.add(createDeleteMessage(UserConfig.getInstance(currentAccount).getNewMessageId(), messagesToResend.keyAt(a), 0, Utilities.random.nextLong(), encryptedChat)); + } + UserConfig.getInstance(currentAccount).saveConfig(false); + } + Collections.sort(messages, (lhs, rhs) -> AndroidUtilities.compare(lhs.seq_out, rhs.seq_out)); + ArrayList encryptedChats = new ArrayList<>(); + encryptedChats.add(encryptedChat); + + AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + MessageObject messageObject = new MessageObject(currentAccount, message, false); + messageObject.resendAsIs = true; + SendMessagesHelper.getInstance(currentAccount).retrySendMessage(messageObject, true); + } + }); + + SendMessagesHelper.getInstance(currentAccount).processUnsentMessages(messages, new ArrayList<>(), new ArrayList<>(), encryptedChats); + MessagesStorage.getInstance(currentAccount).getDatabase().executeFast(String.format(Locale.US, "REPLACE INTO requested_holes VALUES(%d, %d, %d)", encryptedChat.id, sSeq, endSeq)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -1415,16 +1362,13 @@ public class SecretChatHelper { if (holes == null) { return; } - Collections.sort(holes, new Comparator() { - @Override - public int compare(TL_decryptedMessageHolder lhs, TL_decryptedMessageHolder rhs) { - if (lhs.layer.out_seq_no > rhs.layer.out_seq_no) { - return 1; - } else if (lhs.layer.out_seq_no < rhs.layer.out_seq_no) { - return -1; - } - return 0; + Collections.sort(holes, (lhs, rhs) -> { + if (lhs.layer.out_seq_no > rhs.layer.out_seq_no) { + return 1; + } else if (lhs.layer.out_seq_no < rhs.layer.out_seq_no) { + return -1; } + return 0; }); boolean update = false; @@ -1598,13 +1542,10 @@ public class SecretChatHelper { newChat.key_use_count_out = chat.key_use_count_out; newChat.seq_in = chat.seq_in; newChat.seq_out = chat.seq_out; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); - MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); - } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); + MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); }); declineSecretChat(chat.id); return null; @@ -1695,7 +1636,7 @@ public class SecretChatHelper { byte[] correctedAuth = new byte[256]; System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; + correctedAuth[a] = 0; } authKey = correctedAuth; } @@ -1710,12 +1651,9 @@ public class SecretChatHelper { encryptedChat.seq_out = 1; MessagesStorage.getInstance(currentAccount).updateEncryptedChat(encryptedChat); MessagesController.getInstance(currentAccount).putEncryptedChat(encryptedChat, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat); - sendNotifyLayerMessage(encryptedChat, null); - } + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat); + sendNotifyLayerMessage(encryptedChat, null); }); } else { final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); @@ -1730,12 +1668,9 @@ public class SecretChatHelper { newChat.admin_id = encryptedChat.admin_id; newChat.mtproto_seq = encryptedChat.mtproto_seq; MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); - } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); }); declineSecretChat(encryptedChat.id); } @@ -1744,11 +1679,8 @@ public class SecretChatHelper { public void declineSecretChat(int chat_id) { TLRPC.TL_messages_discardEncryption req = new TLRPC.TL_messages_discardEncryption(); req.chat_id = chat_id; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -1760,103 +1692,94 @@ public class SecretChatHelper { TLRPC.TL_messages_getDhConfig req = new TLRPC.TL_messages_getDhConfig(); req.random_length = 256; req.version = MessagesStorage.getInstance(currentAccount).getLastSecretVersion(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; - if (response instanceof TLRPC.TL_messages_dhConfig) { - if (!Utilities.isGoodPrime(res.p, res.g)) { - acceptingChats.remove(encryptedChat.id); - declineSecretChat(encryptedChat.id); - return; - } - - MessagesStorage.getInstance(currentAccount).setSecretPBytes(res.p); - MessagesStorage.getInstance(currentAccount).setSecretG(res.g); - MessagesStorage.getInstance(currentAccount).setLastSecretVersion(res.version); - MessagesStorage.getInstance(currentAccount).saveSecretParams(MessagesStorage.getInstance(currentAccount).getLastSecretVersion(), MessagesStorage.getInstance(currentAccount).getSecretG(), MessagesStorage.getInstance(currentAccount).getSecretPBytes()); - } - byte[] salt = new byte[256]; - for (int a = 0; a < 256; a++) { - salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); - } - encryptedChat.a_or_b = salt; - encryptedChat.seq_in = -1; - encryptedChat.seq_out = 0; - BigInteger p = new BigInteger(1, MessagesStorage.getInstance(currentAccount).getSecretPBytes()); - BigInteger g_b = BigInteger.valueOf(MessagesStorage.getInstance(currentAccount).getSecretG()); - g_b = g_b.modPow(new BigInteger(1, salt), p); - BigInteger g_a = new BigInteger(1, encryptedChat.g_a); - - if (!Utilities.isGoodGaAndGb(g_a, p)) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; + if (response instanceof TLRPC.TL_messages_dhConfig) { + if (!Utilities.isGoodPrime(res.p, res.g)) { acceptingChats.remove(encryptedChat.id); declineSecretChat(encryptedChat.id); return; } - byte[] g_b_bytes = g_b.toByteArray(); - if (g_b_bytes.length > 256) { - byte[] correctedAuth = new byte[256]; - System.arraycopy(g_b_bytes, 1, correctedAuth, 0, 256); - g_b_bytes = correctedAuth; - } - - g_a = g_a.modPow(new BigInteger(1, salt), p); - - byte[] authKey = g_a.toByteArray(); - if (authKey.length > 256) { - byte[] correctedAuth = new byte[256]; - System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); - authKey = correctedAuth; - } else if (authKey.length < 256) { - byte[] correctedAuth = new byte[256]; - System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); - for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; - } - authKey = correctedAuth; - } - byte[] authKeyHash = Utilities.computeSHA1(authKey); - byte[] authKeyId = new byte[8]; - System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); - encryptedChat.auth_key = authKey; - encryptedChat.key_create_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - - TLRPC.TL_messages_acceptEncryption req2 = new TLRPC.TL_messages_acceptEncryption(); - req2.g_b = g_b_bytes; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = encryptedChat.id; - req2.peer.access_hash = encryptedChat.access_hash; - req2.key_fingerprint = Utilities.bytesToLong(authKeyId); - ConnectionsManager.getInstance(currentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - acceptingChats.remove(encryptedChat.id); - if (error == null) { - final TLRPC.EncryptedChat newChat = (TLRPC.EncryptedChat) response; - newChat.auth_key = encryptedChat.auth_key; - newChat.user_id = encryptedChat.user_id; - newChat.seq_in = encryptedChat.seq_in; - newChat.seq_out = encryptedChat.seq_out; - newChat.key_create_date = encryptedChat.key_create_date; - newChat.key_use_count_in = encryptedChat.key_use_count_in; - newChat.key_use_count_out = encryptedChat.key_use_count_out; - MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); - MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); - sendNotifyLayerMessage(newChat, null); - } - }); - } - } - }); - } else { - acceptingChats.remove(encryptedChat.id); + MessagesStorage.getInstance(currentAccount).setSecretPBytes(res.p); + MessagesStorage.getInstance(currentAccount).setSecretG(res.g); + MessagesStorage.getInstance(currentAccount).setLastSecretVersion(res.version); + MessagesStorage.getInstance(currentAccount).saveSecretParams(MessagesStorage.getInstance(currentAccount).getLastSecretVersion(), MessagesStorage.getInstance(currentAccount).getSecretG(), MessagesStorage.getInstance(currentAccount).getSecretPBytes()); } + byte[] salt = new byte[256]; + for (int a = 0; a < 256; a++) { + salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); + } + encryptedChat.a_or_b = salt; + encryptedChat.seq_in = -1; + encryptedChat.seq_out = 0; + BigInteger p = new BigInteger(1, MessagesStorage.getInstance(currentAccount).getSecretPBytes()); + BigInteger g_b = BigInteger.valueOf(MessagesStorage.getInstance(currentAccount).getSecretG()); + g_b = g_b.modPow(new BigInteger(1, salt), p); + BigInteger g_a = new BigInteger(1, encryptedChat.g_a); + + if (!Utilities.isGoodGaAndGb(g_a, p)) { + acceptingChats.remove(encryptedChat.id); + declineSecretChat(encryptedChat.id); + return; + } + + byte[] g_b_bytes = g_b.toByteArray(); + if (g_b_bytes.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_b_bytes, 1, correctedAuth, 0, 256); + g_b_bytes = correctedAuth; + } + + g_a = g_a.modPow(new BigInteger(1, salt), p); + + byte[] authKey = g_a.toByteArray(); + if (authKey.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); + authKey = correctedAuth; + } else if (authKey.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); + for (int a = 0; a < 256 - authKey.length; a++) { + correctedAuth[a] = 0; + } + authKey = correctedAuth; + } + byte[] authKeyHash = Utilities.computeSHA1(authKey); + byte[] authKeyId = new byte[8]; + System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); + encryptedChat.auth_key = authKey; + encryptedChat.key_create_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + + TLRPC.TL_messages_acceptEncryption req2 = new TLRPC.TL_messages_acceptEncryption(); + req2.g_b = g_b_bytes; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = encryptedChat.id; + req2.peer.access_hash = encryptedChat.access_hash; + req2.key_fingerprint = Utilities.bytesToLong(authKeyId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> { + acceptingChats.remove(encryptedChat.id); + if (error1 == null) { + final TLRPC.EncryptedChat newChat = (TLRPC.EncryptedChat) response1; + newChat.auth_key = encryptedChat.auth_key; + newChat.user_id = encryptedChat.user_id; + newChat.seq_in = encryptedChat.seq_in; + newChat.seq_out = encryptedChat.seq_out; + newChat.key_create_date = encryptedChat.key_create_date; + newChat.key_use_count_in = encryptedChat.key_use_count_in; + newChat.key_use_count_out = encryptedChat.key_use_count_out; + MessagesStorage.getInstance(currentAccount).updateEncryptedChat(newChat); + MessagesController.getInstance(currentAccount).putEncryptedChat(newChat, false); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + sendNotifyLayerMessage(newChat, null); + }); + } + }); + } else { + acceptingChats.remove(encryptedChat.id); } }); } @@ -1873,121 +1796,48 @@ public class SecretChatHelper { TLRPC.TL_messages_getDhConfig req = new TLRPC.TL_messages_getDhConfig(); req.random_length = 256; req.version = MessagesStorage.getInstance(currentAccount).getLastSecretVersion(); - final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; - if (response instanceof TLRPC.TL_messages_dhConfig) { - if (!Utilities.isGoodPrime(res.p, res.g)) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - if (!((Activity) context).isFinishing()) { - progressDialog.dismiss(); - } - } catch (Exception e) { - FileLog.e(e); - } + final int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; + if (response instanceof TLRPC.TL_messages_dhConfig) { + if (!Utilities.isGoodPrime(res.p, res.g)) { + AndroidUtilities.runOnUIThread(() -> { + try { + if (!((Activity) context).isFinishing()) { + progressDialog.dismiss(); } - }); - return; - } - MessagesStorage.getInstance(currentAccount).setSecretPBytes(res.p); - MessagesStorage.getInstance(currentAccount).setSecretG(res.g); - MessagesStorage.getInstance(currentAccount).setLastSecretVersion(res.version); - MessagesStorage.getInstance(currentAccount).saveSecretParams(MessagesStorage.getInstance(currentAccount).getLastSecretVersion(), MessagesStorage.getInstance(currentAccount).getSecretG(), MessagesStorage.getInstance(currentAccount).getSecretPBytes()); - } - final byte[] salt = new byte[256]; - for (int a = 0; a < 256; a++) { - salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); - } - - BigInteger i_g_a = BigInteger.valueOf(MessagesStorage.getInstance(currentAccount).getSecretG()); - i_g_a = i_g_a.modPow(new BigInteger(1, salt), new BigInteger(1, MessagesStorage.getInstance(currentAccount).getSecretPBytes())); - byte[] g_a = i_g_a.toByteArray(); - if (g_a.length > 256) { - byte[] correctedAuth = new byte[256]; - System.arraycopy(g_a, 1, correctedAuth, 0, 256); - g_a = correctedAuth; - } - - TLRPC.TL_messages_requestEncryption req2 = new TLRPC.TL_messages_requestEncryption(); - req2.g_a = g_a; - req2.user_id = MessagesController.getInstance(currentAccount).getInputUser(user); - req2.random_id = Utilities.random.nextInt(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (error == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - startingSecretChat = false; - if (!((Activity) context).isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) response; - chat.user_id = chat.participant_id; - chat.seq_in = -2; - chat.seq_out = 1; - chat.a_or_b = salt; - MessagesController.getInstance(currentAccount).putEncryptedChat(chat, false); - TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); - dialog.id = ((long) chat.id) << 32; - dialog.unread_count = 0; - dialog.top_message = 0; - dialog.last_message_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - MessagesController.getInstance(currentAccount).dialogs_dict.put(dialog.id, dialog); - MessagesController.getInstance(currentAccount).dialogs.add(dialog); - MessagesController.getInstance(currentAccount).sortDialogs(null); - MessagesStorage.getInstance(currentAccount).putEncryptedChat(chat, user, dialog); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatCreated, chat); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (!delayedEncryptedChatUpdates.isEmpty()) { - MessagesController.getInstance(currentAccount).processUpdateArray(delayedEncryptedChatUpdates, null, null, false); - delayedEncryptedChatUpdates.clear(); - } - } - }); - } - }); - } else { - delayedEncryptedChatUpdates.clear(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!((Activity) context).isFinishing()) { - startingSecretChat = false; - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("CreateEncryptedChatError", R.string.CreateEncryptedChatError)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.show().setCanceledOnTouchOutside(true); - } - } - }); + } catch (Exception e) { + FileLog.e(e); } - } - }, ConnectionsManager.RequestFlagFailOnServerErrors); - } else { - delayedEncryptedChatUpdates.clear(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { + }); + return; + } + MessagesStorage.getInstance(currentAccount).setSecretPBytes(res.p); + MessagesStorage.getInstance(currentAccount).setSecretG(res.g); + MessagesStorage.getInstance(currentAccount).setLastSecretVersion(res.version); + MessagesStorage.getInstance(currentAccount).saveSecretParams(MessagesStorage.getInstance(currentAccount).getLastSecretVersion(), MessagesStorage.getInstance(currentAccount).getSecretG(), MessagesStorage.getInstance(currentAccount).getSecretPBytes()); + } + final byte[] salt = new byte[256]; + for (int a = 0; a < 256; a++) { + salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); + } + + BigInteger i_g_a = BigInteger.valueOf(MessagesStorage.getInstance(currentAccount).getSecretG()); + i_g_a = i_g_a.modPow(new BigInteger(1, salt), new BigInteger(1, MessagesStorage.getInstance(currentAccount).getSecretPBytes())); + byte[] g_a = i_g_a.toByteArray(); + if (g_a.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_a, 1, correctedAuth, 0, 256); + g_a = correctedAuth; + } + + TLRPC.TL_messages_requestEncryption req2 = new TLRPC.TL_messages_requestEncryption(); + req2.g_a = g_a; + req2.user_id = MessagesController.getInstance(currentAccount).getInputUser(user); + req2.random_id = Utilities.random.nextInt(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> { + if (error1 == null) { + AndroidUtilities.runOnUIThread(() -> { startingSecretChat = false; if (!((Activity) context).isFinishing()) { try { @@ -1996,20 +1846,69 @@ public class SecretChatHelper { FileLog.e(e); } } + TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) response1; + chat.user_id = chat.participant_id; + chat.seq_in = -2; + chat.seq_out = 1; + chat.a_or_b = salt; + MessagesController.getInstance(currentAccount).putEncryptedChat(chat, false); + TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); + dialog.id = ((long) chat.id) << 32; + dialog.unread_count = 0; + dialog.top_message = 0; + dialog.last_message_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + MessagesController.getInstance(currentAccount).dialogs_dict.put(dialog.id, dialog); + MessagesController.getInstance(currentAccount).dialogs.add(dialog); + MessagesController.getInstance(currentAccount).sortDialogs(null); + MessagesStorage.getInstance(currentAccount).putEncryptedChat(chat, user, dialog); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.encryptedChatCreated, chat); + Utilities.stageQueue.postRunnable(() -> { + if (!delayedEncryptedChatUpdates.isEmpty()) { + MessagesController.getInstance(currentAccount).processUpdateArray(delayedEncryptedChatUpdates, null, null, false); + delayedEncryptedChatUpdates.clear(); + } + }); + }); + } else { + delayedEncryptedChatUpdates.clear(); + AndroidUtilities.runOnUIThread(() -> { + if (!((Activity) context).isFinishing()) { + startingSecretChat = false; + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("CreateEncryptedChatError", R.string.CreateEncryptedChatError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.show().setCanceledOnTouchOutside(true); + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + delayedEncryptedChatUpdates.clear(); + AndroidUtilities.runOnUIThread(() -> { + startingSecretChat = false; + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } - }); - } + } + }); } }, ConnectionsManager.RequestFlagFailOnServerErrors); - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); try { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecureDocument.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecureDocument.java index 2e23fbe44..aa5e442e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecureDocument.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecureDocument.java @@ -11,6 +11,7 @@ public class SecureDocument extends TLObject { public TLRPC.TL_inputFile inputFile; public byte[] fileSecret; public byte[] fileHash; + public int type; public SecureDocument(SecureDocumentKey key, TLRPC.TL_secureFile file, String p, byte[] fh, byte[] secret) { secureDocumentKey = key; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index e49ec80da..2d9d3bfe8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -48,7 +48,6 @@ import org.telegram.messenger.audioinfo.AudioInfo; import org.telegram.messenger.support.SparseLongArray; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.QuickAckDelegate; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; @@ -90,7 +89,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { cores = 2; } - mediaSendThreadPool = new ThreadPoolExecutor(cores, cores, 60, TimeUnit.SECONDS, new LinkedBlockingQueue()); + mediaSendThreadPool = new ThreadPoolExecutor(cores, cores, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); } private static class MediaSendPrepareWorker { @@ -365,19 +364,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter public SendMessagesHelper(int instance) { currentAccount = instance; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidUpload); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidFailUpload); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FilePreparingStarted); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileNewChunkAvailable); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FilePreparingFailed); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.httpFileDidFailedLoad); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.httpFileDidLoaded); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidLoaded); - NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidFailedLoad); - } + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidUpload); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidFailUpload); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FilePreparingStarted); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileNewChunkAvailable); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FilePreparingFailed); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.httpFileDidFailedLoad); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.httpFileDidLoaded); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance(currentAccount).addObserver(SendMessagesHelper.this, NotificationCenter.FileDidFailedLoad); }); } @@ -660,74 +656,62 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (fileType == 0) { String md5 = Utilities.MD5(path) + "." + ImageLoader.getHttpUrlExtension(path, "file"); final File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - final TLRPC.TL_photo photo = generatePhotoSizes(cacheFile.toString(), null); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (photo != null) { - messageObject.messageOwner.media.photo = photo; - messageObject.messageOwner.attachPath = cacheFile.toString(); - ArrayList messages = new ArrayList<>(); - messages.add(messageObject.messageOwner); - MessagesStorage.getInstance(currentAccount).putMessages(messages, false, true, false, 0); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, messageObject.messageOwner); - message.location = photo.sizes.get(photo.sizes.size() - 1).location; - message.httpLocation = null; - if (message.type == 4) { - performSendDelayedMessage(message, message.messageObjects.indexOf(messageObject)); - } else { - performSendDelayedMessage(message); - } - } else { - if (BuildVars.LOGS_ENABLED) { - FileLog.e("can't load image " + path + " to file " + cacheFile.toString()); - } - message.markAsError(); - } + Utilities.globalQueue.postRunnable(() -> { + final TLRPC.TL_photo photo = generatePhotoSizes(cacheFile.toString(), null); + AndroidUtilities.runOnUIThread(() -> { + if (photo != null) { + messageObject.messageOwner.media.photo = photo; + messageObject.messageOwner.attachPath = cacheFile.toString(); + ArrayList messages = new ArrayList<>(); + messages.add(messageObject.messageOwner); + MessagesStorage.getInstance(currentAccount).putMessages(messages, false, true, false, 0); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, messageObject.messageOwner); + message.location = photo.sizes.get(photo.sizes.size() - 1).location; + message.httpLocation = null; + if (message.type == 4) { + performSendDelayedMessage(message, message.messageObjects.indexOf(messageObject)); + } else { + performSendDelayedMessage(message); } - }); - } + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("can't load image " + path + " to file " + cacheFile.toString()); + } + message.markAsError(); + } + }); }); } else if (fileType == 1) { String md5 = Utilities.MD5(path) + ".gif"; final File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - final TLRPC.Document document = message.obj.getDocument(); - if (document.thumb.location instanceof TLRPC.TL_fileLocationUnavailable) { - try { - Bitmap bitmap = ImageLoader.loadBitmap(cacheFile.getAbsolutePath(), null, 90, 90, true); - if (bitmap != null) { - document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, message.sendEncryptedRequest != null); - bitmap.recycle(); - } - } catch (Exception e) { - document.thumb = null; - FileLog.e(e); - } - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; + Utilities.globalQueue.postRunnable(() -> { + final TLRPC.Document document = message.obj.getDocument(); + if (document.thumb.location instanceof TLRPC.TL_fileLocationUnavailable) { + try { + Bitmap bitmap = ImageLoader.loadBitmap(cacheFile.getAbsolutePath(), null, 90, 90, true); + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, message.sendEncryptedRequest != null); + bitmap.recycle(); } + } catch (Exception e) { + document.thumb = null; + FileLog.e(e); + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - message.httpLocation = null; - message.obj.messageOwner.attachPath = cacheFile.toString(); - message.location = document.thumb.location; - ArrayList messages = new ArrayList<>(); - messages.add(messageObject.messageOwner); - MessagesStorage.getInstance(currentAccount).putMessages(messages, false, true, false, 0); - performSendDelayedMessage(message); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, message.obj.messageOwner); - } - }); } + AndroidUtilities.runOnUIThread(() -> { + message.httpLocation = null; + message.obj.messageOwner.attachPath = cacheFile.toString(); + message.location = document.thumb.location; + ArrayList messages = new ArrayList<>(); + messages.add(messageObject.messageOwner); + MessagesStorage.getInstance(currentAccount).putMessages(messages, false, true, false, 0); + performSendDelayedMessage(message); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateMessageMedia, message.obj.messageOwner); + }); }); } } @@ -1325,118 +1309,101 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter final ArrayList newMsgArr = objArr; final LongSparseArray messagesByRandomIdsFinal = messagesByRandomIds; final boolean isMegagroupFinal = isMegagroup; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - SparseLongArray newMessagesByIds = new SparseLongArray(); - TLRPC.Updates updates = (TLRPC.Updates) response; - for (int a = 0; a < updates.updates.size(); a++) { - TLRPC.Update update = updates.updates.get(a); - if (update instanceof TLRPC.TL_updateMessageID) { - TLRPC.TL_updateMessageID updateMessageID = (TLRPC.TL_updateMessageID) update; - newMessagesByIds.put(updateMessageID.id, updateMessageID.random_id); - updates.updates.remove(a); - a--; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + SparseLongArray newMessagesByIds = new SparseLongArray(); + TLRPC.Updates updates = (TLRPC.Updates) response; + for (int a1 = 0; a1 < updates.updates.size(); a1++) { + TLRPC.Update update = updates.updates.get(a1); + if (update instanceof TLRPC.TL_updateMessageID) { + TLRPC.TL_updateMessageID updateMessageID = (TLRPC.TL_updateMessageID) update; + newMessagesByIds.put(updateMessageID.id, updateMessageID.random_id); + updates.updates.remove(a1); + a1--; + } + } + Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(peer); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, peer); + MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(peer, value); + } + + int sentCount = 0; + for (int a1 = 0; a1 < updates.updates.size(); a1++) { + TLRPC.Update update = updates.updates.get(a1); + if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) { + updates.updates.remove(a1); + a1--; + final TLRPC.Message message; + if (update instanceof TLRPC.TL_updateNewMessage) { + TLRPC.TL_updateNewMessage updateNewMessage = (TLRPC.TL_updateNewMessage) update; + message = updateNewMessage.message; + MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, updateNewMessage.pts, -1, updateNewMessage.pts_count); + } else { + TLRPC.TL_updateNewChannelMessage updateNewChannelMessage = (TLRPC.TL_updateNewChannelMessage) update; + message = updateNewChannelMessage.message; + MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(updateNewChannelMessage.pts, updateNewChannelMessage.pts_count, message.to_id.channel_id); + if (isMegagroupFinal) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + ImageLoader.saveMessageThumbs(message); + message.unread = value < message.id; + if (toMyself) { + message.out = true; + message.unread = false; + message.media_unread = false; } - } - Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(peer); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(true, peer); - MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(peer, value); - } - int sentCount = 0; - for (int a = 0; a < updates.updates.size(); a++) { - TLRPC.Update update = updates.updates.get(a); - if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) { - updates.updates.remove(a); - a--; - final TLRPC.Message message; - if (update instanceof TLRPC.TL_updateNewMessage) { - TLRPC.TL_updateNewMessage updateNewMessage = (TLRPC.TL_updateNewMessage) update; - message = updateNewMessage.message; - MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, updateNewMessage.pts, -1, updateNewMessage.pts_count); - } else { - TLRPC.TL_updateNewChannelMessage updateNewChannelMessage = (TLRPC.TL_updateNewChannelMessage) update; - message = updateNewChannelMessage.message; - MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(updateNewChannelMessage.pts, updateNewChannelMessage.pts_count, message.to_id.channel_id); - if (isMegagroupFinal) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } + long random_id = newMessagesByIds.get(message.id); + if (random_id != 0) { + final TLRPC.Message newMsgObj1 = messagesByRandomIdsFinal.get(random_id); + if (newMsgObj1 == null) { + continue; } - ImageLoader.saveMessageThumbs(message); - message.unread = value < message.id; - if (toMyself) { - message.out = true; - message.unread = false; - message.media_unread = false; + int index = newMsgObjArr.indexOf(newMsgObj1); + if (index == -1) { + continue; } - - long random_id = newMessagesByIds.get(message.id); - if (random_id != 0) { - final TLRPC.Message newMsgObj = messagesByRandomIdsFinal.get(random_id); - if (newMsgObj == null) { - continue; - } - int index = newMsgObjArr.indexOf(newMsgObj); - if (index == -1) { - continue; - } - MessageObject msgObj = newMsgArr.get(index); - newMsgObjArr.remove(index); - newMsgArr.remove(index); - final int oldId = newMsgObj.id; - final ArrayList sentMessages = new ArrayList<>(); - sentMessages.add(message); - newMsgObj.id = message.id; - sentCount++; - updateMediaPaths(msgObj, message, null, true); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, oldId, newMsgObj.id, 0, false, to_id.channel_id); - MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, false, 0); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - DataQuery.getInstance(currentAccount).increasePeerRaiting(peer); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, message.id, message, peer, 0L); - processSentMessage(oldId); - removeFromSendingMessages(oldId); - } - }); - } + MessageObject msgObj1 = newMsgArr.get(index); + newMsgObjArr.remove(index); + newMsgArr.remove(index); + final int oldId = newMsgObj1.id; + final ArrayList sentMessages = new ArrayList<>(); + sentMessages.add(message); + newMsgObj1.id = message.id; + sentCount++; + updateMediaPaths(msgObj1, message, null, true); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj1.random_id, oldId, newMsgObj1.id, 0, false, to_id.channel_id); + MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, false, 0); + AndroidUtilities.runOnUIThread(() -> { + newMsgObj1.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + DataQuery.getInstance(currentAccount).increasePeerRaiting(peer); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, message.id, message, peer, 0L); + processSentMessage(oldId); + removeFromSendingMessages(oldId); }); - } + }); } } - if (!updates.updates.isEmpty()) { - MessagesController.getInstance(currentAccount).processUpdates(updates, false); - } - StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, sentCount); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, null, req); - } - }); } - for (int a = 0; a < newMsgObjArr.size(); a++) { - final TLRPC.Message newMsgObj = newMsgObjArr.get(a); - MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); - processSentMessage(newMsgObj.id); - removeFromSendingMessages(newMsgObj.id); - } - }); + if (!updates.updates.isEmpty()) { + MessagesController.getInstance(currentAccount).processUpdates(updates, false); } + StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, sentCount); + } else { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, null, req)); + } + for (int a1 = 0; a1 < newMsgObjArr.size(); a1++) { + final TLRPC.Message newMsgObj1 = newMsgObjArr.get(a1); + MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj1); + AndroidUtilities.runOnUIThread(() -> { + newMsgObj1.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj1.id); + processSentMessage(newMsgObj1.id); + removeFromSendingMessages(newMsgObj1.id); + }); } }, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter); @@ -1756,26 +1723,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter req.entities = entities; req.flags |= 8; } - return ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error == null) { - MessagesController.getInstance(currentAccount).processUpdates((TLRPC.Updates) response, false); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, fragment, req); - } - }); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - callback.run(); - } - }); + return ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + MessagesController.getInstance(currentAccount).processUpdates((TLRPC.Updates) response, false); + } else { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.processError(currentAccount, error, fragment, req)); } + AndroidUtilities.runOnUIThread(callback); }); } @@ -1808,52 +1762,39 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } public void sendNotificationCallback(final long dialogId, final int msgId, final byte[] data) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - int lowerId = (int) dialogId; - final String key = dialogId + "_" + msgId + "_" + Utilities.bytesToHex(data) + "_" + 0; - waitingForCallback.put(key, true); + AndroidUtilities.runOnUIThread(() -> { + int lowerId = (int) dialogId; + final String key = dialogId + "_" + msgId + "_" + Utilities.bytesToHex(data) + "_" + 0; + waitingForCallback.put(key, true); - if (lowerId > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lowerId); - if (user == null) { - user = MessagesStorage.getInstance(currentAccount).getUserSync(lowerId); - if (user != null) { - MessagesController.getInstance(currentAccount).putUser(user, true); - } - } - } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lowerId); - if (chat == null) { - chat = MessagesStorage.getInstance(currentAccount).getChatSync(-lowerId); - if (chat != null) { - MessagesController.getInstance(currentAccount).putChat(chat, true); - } + if (lowerId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lowerId); + if (user == null) { + user = MessagesStorage.getInstance(currentAccount).getUserSync(lowerId); + if (user != null) { + MessagesController.getInstance(currentAccount).putUser(user, true); } } - - TLRPC.TL_messages_getBotCallbackAnswer req = new TLRPC.TL_messages_getBotCallbackAnswer(); - req.peer = MessagesController.getInstance(currentAccount).getInputPeer(lowerId); - req.msg_id = msgId; - req.game = false; - if (data != null) { - req.flags |= 1; - req.data = data; - } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - waitingForCallback.remove(key); - } - }); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lowerId); + if (chat == null) { + chat = MessagesStorage.getInstance(currentAccount).getChatSync(-lowerId); + if (chat != null) { + MessagesController.getInstance(currentAccount).putChat(chat, true); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); - MessagesController.getInstance(currentAccount).markDialogAsRead(dialogId, msgId, msgId, 0, false, 0, true); + } } + + TLRPC.TL_messages_getBotCallbackAnswer req = new TLRPC.TL_messages_getBotCallbackAnswer(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(lowerId); + req.msg_id = msgId; + req.game = false; + if (data != null) { + req.flags |= 1; + req.data = data; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> waitingForCallback.remove(key)), ConnectionsManager.RequestFlagFailOnServerErrors); + MessagesController.getInstance(currentAccount).markDialogAsRead(dialogId, msgId, msgId, 0, false, 0, true); }); } @@ -1877,87 +1818,79 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter final String key = messageObject.getDialogId() + "_" + messageObject.getId() + "_" + Utilities.bytesToHex(button.data) + "_" + type; waitingForCallback.put(key, true); - RequestDelegate requestDelegate = new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - waitingForCallback.remove(key); - if (cacheFinal && response == null) { - sendCallback(false, messageObject, button, parentFragment); - } else if (response != null) { - if (button instanceof TLRPC.TL_keyboardButtonBuy) { - if (response instanceof TLRPC.TL_payments_paymentForm) { - final TLRPC.TL_payments_paymentForm form = (TLRPC.TL_payments_paymentForm) response; - MessagesController.getInstance(currentAccount).putUsers(form.users, false); - parentFragment.presentFragment(new PaymentFormActivity(form, messageObject)); - } else if (response instanceof TLRPC.TL_payments_paymentReceipt) { - parentFragment.presentFragment(new PaymentFormActivity(messageObject, (TLRPC.TL_payments_paymentReceipt) response)); + RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { + waitingForCallback.remove(key); + if (cacheFinal && response == null) { + sendCallback(false, messageObject, button, parentFragment); + } else if (response != null) { + if (button instanceof TLRPC.TL_keyboardButtonBuy) { + if (response instanceof TLRPC.TL_payments_paymentForm) { + final TLRPC.TL_payments_paymentForm form = (TLRPC.TL_payments_paymentForm) response; + MessagesController.getInstance(currentAccount).putUsers(form.users, false); + parentFragment.presentFragment(new PaymentFormActivity(form, messageObject)); + } else if (response instanceof TLRPC.TL_payments_paymentReceipt) { + parentFragment.presentFragment(new PaymentFormActivity(messageObject, (TLRPC.TL_payments_paymentReceipt) response)); + } + } else { + TLRPC.TL_messages_botCallbackAnswer res = (TLRPC.TL_messages_botCallbackAnswer) response; + if (!cacheFinal && res.cache_time != 0) { + MessagesStorage.getInstance(currentAccount).saveBotCache(key, res); + } + if (res.message != null) { + if (res.alert) { + if (parentFragment.getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(parentFragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setMessage(res.message); + parentFragment.showDialog(builder.create()); + } else { + int uid = messageObject.messageOwner.from_id; + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + String name = null; + if (uid > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); + if (user != null) { + name = ContactsController.formatName(user.first_name, user.last_name); } } else { - TLRPC.TL_messages_botCallbackAnswer res = (TLRPC.TL_messages_botCallbackAnswer) response; - if (!cacheFinal && res.cache_time != 0) { - MessagesStorage.getInstance(currentAccount).saveBotCache(key, res); - } - if (res.message != null) { - if (res.alert) { - if (parentFragment.getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(parentFragment.getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setMessage(res.message); - parentFragment.showDialog(builder.create()); - } else { - int uid = messageObject.messageOwner.from_id; - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } - String name = null; - if (uid > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); - if (user != null) { - name = ContactsController.formatName(user.first_name, user.last_name); - } - } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); - if (chat != null) { - name = chat.title; - } - } - if (name == null) { - name = "bot"; - } - parentFragment.showAlert(name, res.message); - } - } else if (res.url != null) { - if (parentFragment.getParentActivity() == null) { - return; - } - int uid = messageObject.messageOwner.from_id; - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); - boolean verified = user != null && user.verified; - if (button instanceof TLRPC.TL_keyboardButtonGame) { - TLRPC.TL_game game = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame ? messageObject.messageOwner.media.game : null; - if (game == null) { - return; - } - parentFragment.showOpenGameAlert(game, messageObject, res.url, !verified && MessagesController.getNotificationsSettings(currentAccount).getBoolean("askgame_" + uid, true), uid); - } else { - parentFragment.showOpenUrlAlert(res.url, false); - } + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); + if (chat != null) { + name = chat.title; } } + if (name == null) { + name = "bot"; + } + parentFragment.showAlert(name, res.message); + } + } else if (res.url != null) { + if (parentFragment.getParentActivity() == null) { + return; + } + int uid = messageObject.messageOwner.from_id; + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); + boolean verified = user != null && user.verified; + if (button instanceof TLRPC.TL_keyboardButtonGame) { + TLRPC.TL_game game = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame ? messageObject.messageOwner.media.game : null; + if (game == null) { + return; + } + parentFragment.showOpenGameAlert(game, messageObject, res.url, !verified && MessagesController.getNotificationsSettings(currentAccount).getBoolean("askgame_" + uid, true), uid); + } else { + parentFragment.showOpenUrlAlert(res.url, false); } } - }); + } } - }; + }); if (cacheFinal) { MessagesStorage.getInstance(currentAccount).getBotCache(key, requestDelegate); } else { @@ -2029,15 +1962,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { newTaskId = taskId; } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (error == null) { - MessagesController.getInstance(currentAccount).processUpdates((TLRPC.Updates) response, false); - } - if (newTaskId != 0) { - MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + if (error == null) { + MessagesController.getInstance(currentAccount).processUpdates((TLRPC.Updates) response, false); + } + if (newTaskId != 0) { + MessagesStorage.getInstance(currentAccount).removePendingTask(newTaskId); } }); } @@ -3413,49 +3343,41 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.TL_messages_uploadMedia req = new TLRPC.TL_messages_uploadMedia(); req.media = inputMedia; req.peer = ((TLRPC.TL_messages_sendMultiMedia) message.sendRequest).peer; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.InputMedia newInputMedia = null; - if (response != null) { - TLRPC.MessageMedia messageMedia = (TLRPC.MessageMedia) response; - if (inputMedia instanceof TLRPC.TL_inputMediaUploadedPhoto && messageMedia instanceof TLRPC.TL_messageMediaPhoto) { - TLRPC.TL_inputMediaPhoto inputMediaPhoto = new TLRPC.TL_inputMediaPhoto(); - inputMediaPhoto.id = new TLRPC.TL_inputPhoto(); - inputMediaPhoto.id.id = messageMedia.photo.id; - inputMediaPhoto.id.access_hash = messageMedia.photo.access_hash; - newInputMedia = inputMediaPhoto; - } else if (inputMedia instanceof TLRPC.TL_inputMediaUploadedDocument && messageMedia instanceof TLRPC.TL_messageMediaDocument) { - TLRPC.TL_inputMediaDocument inputMediaDocument = new TLRPC.TL_inputMediaDocument(); - inputMediaDocument.id = new TLRPC.TL_inputDocument(); - inputMediaDocument.id.id = messageMedia.document.id; - inputMediaDocument.id.access_hash = messageMedia.document.access_hash; - newInputMedia = inputMediaDocument; - } - } - if (newInputMedia != null) { - if (inputMedia.ttl_seconds != 0) { - newInputMedia.ttl_seconds = inputMedia.ttl_seconds; - newInputMedia.flags |= 1; - } - TLRPC.TL_messages_sendMultiMedia req = (TLRPC.TL_messages_sendMultiMedia) message.sendRequest; - for (int a = 0; a < req.multi_media.size(); a++) { - if (req.multi_media.get(a).media == inputMedia) { - req.multi_media.get(a).media = newInputMedia; - break; - } - } - sendReadyToSendGroup(message, false, true); - } else { - message.markAsError(); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.InputMedia newInputMedia = null; + if (response != null) { + TLRPC.MessageMedia messageMedia = (TLRPC.MessageMedia) response; + if (inputMedia instanceof TLRPC.TL_inputMediaUploadedPhoto && messageMedia instanceof TLRPC.TL_messageMediaPhoto) { + TLRPC.TL_inputMediaPhoto inputMediaPhoto = new TLRPC.TL_inputMediaPhoto(); + inputMediaPhoto.id = new TLRPC.TL_inputPhoto(); + inputMediaPhoto.id.id = messageMedia.photo.id; + inputMediaPhoto.id.access_hash = messageMedia.photo.access_hash; + newInputMedia = inputMediaPhoto; + } else if (inputMedia instanceof TLRPC.TL_inputMediaUploadedDocument && messageMedia instanceof TLRPC.TL_messageMediaDocument) { + TLRPC.TL_inputMediaDocument inputMediaDocument = new TLRPC.TL_inputMediaDocument(); + inputMediaDocument.id = new TLRPC.TL_inputDocument(); + inputMediaDocument.id.id = messageMedia.document.id; + inputMediaDocument.id.access_hash = messageMedia.document.access_hash; + newInputMedia = inputMediaDocument; + } } - }); + if (newInputMedia != null) { + if (inputMedia.ttl_seconds != 0) { + newInputMedia.ttl_seconds = inputMedia.ttl_seconds; + newInputMedia.flags |= 1; + } + TLRPC.TL_messages_sendMultiMedia req1 = (TLRPC.TL_messages_sendMultiMedia) message.sendRequest; + for (int a = 0; a < req1.multi_media.size(); a++) { + if (req1.multi_media.get(a).media == inputMedia) { + req1.multi_media.get(a).media = newInputMedia; + break; + } + } + sendReadyToSendGroup(message, false, true); + } else { + message.markAsError(); + } + })); } else if (inputEncryptedFile != null) { TLRPC.TL_messages_sendEncryptedMultiMedia multiMedia = (TLRPC.TL_messages_sendEncryptedMultiMedia) message.sendEncryptedRequest; for (int a = 0; a < multiMedia.files.size(); a++) { @@ -3525,17 +3447,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } protected void stopVideoService(final String path) { - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopEncodingService, path, currentAccount); - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopEncodingService, path, currentAccount))); } protected void putToSendingMessages(TLRPC.Message message) { @@ -3558,132 +3470,103 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter for (int a = 0; a < msgObjs.size(); a++) { putToSendingMessages(msgObjs.get(a).messageOwner); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - boolean isSentError = false; - if (error == null) { - SparseArray newMessages = new SparseArray<>(); - LongSparseArray newIds = new LongSparseArray<>(); - final TLRPC.Updates updates = (TLRPC.Updates) response; - ArrayList updatesArr = ((TLRPC.Updates) response).updates; - for (int a = 0; a < updatesArr.size(); a++) { - TLRPC.Update update = updatesArr.get(a); - if (update instanceof TLRPC.TL_updateMessageID) { - TLRPC.TL_updateMessageID updateMessageID = (TLRPC.TL_updateMessageID) update; - newIds.put(updateMessageID.random_id, updateMessageID.id); - updatesArr.remove(a); - a--; - } else if (update instanceof TLRPC.TL_updateNewMessage) { - final TLRPC.TL_updateNewMessage newMessage = (TLRPC.TL_updateNewMessage) update; - newMessages.put(newMessage.message.id, newMessage.message); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, newMessage.pts, -1, newMessage.pts_count); - } - }); - updatesArr.remove(a); - a--; - } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { - final TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; - newMessages.put(newMessage.message.id, newMessage.message); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id); - } - }); - updatesArr.remove(a); - a--; - } - } - - for (int i = 0; i < msgObjs.size(); i++) { - final MessageObject msgObj = msgObjs.get(i); - final String originalPath = originalPaths.get(i); - final TLRPC.Message newMsgObj = msgObj.messageOwner; - final int oldId = newMsgObj.id; - final ArrayList sentMessages = new ArrayList<>(); - final String attachPath = newMsgObj.attachPath; - final long grouped_id; - - Integer id = newIds.get(newMsgObj.random_id); - if (id != null) { - TLRPC.Message message = newMessages.get(id); - if (message != null) { - sentMessages.add(message); - newMsgObj.id = message.id; - if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { - message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - grouped_id = message.grouped_id; - - Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(message.dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); - MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(message.dialog_id, value); - } - message.unread = value < message.id; - updateMediaPaths(msgObj, message, originalPath, false); - } else { - isSentError = true; - break; - } - } else { - isSentError = true; - break; - } - - if (!isSentError) { - StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, 1); - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, oldId, newMsgObj.id, 0, false, newMsgObj.to_id.channel_id); - MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, false, 0); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - DataQuery.getInstance(currentAccount).increasePeerRaiting(newMsgObj.dialog_id); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id); - processSentMessage(oldId); - removeFromSendingMessages(oldId); - } - }); - } - }); - } - } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processUpdates(updates, false); - } - }); - } else { - AlertsCreator.processError(currentAccount, error, null, req); - isSentError = true; - } - if (isSentError) { - for (int i = 0; i < msgObjs.size(); i++) { - TLRPC.Message newMsgObj = msgObjs.get(i).messageOwner; - MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); - processSentMessage(newMsgObj.id); - removeFromSendingMessages(newMsgObj.id); - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + boolean isSentError = false; + if (error == null) { + SparseArray newMessages = new SparseArray<>(); + LongSparseArray newIds = new LongSparseArray<>(); + final TLRPC.Updates updates = (TLRPC.Updates) response; + ArrayList updatesArr = ((TLRPC.Updates) response).updates; + for (int a = 0; a < updatesArr.size(); a++) { + TLRPC.Update update = updatesArr.get(a); + if (update instanceof TLRPC.TL_updateMessageID) { + TLRPC.TL_updateMessageID updateMessageID = (TLRPC.TL_updateMessageID) update; + newIds.put(updateMessageID.random_id, updateMessageID.id); + updatesArr.remove(a); + a--; + } else if (update instanceof TLRPC.TL_updateNewMessage) { + final TLRPC.TL_updateNewMessage newMessage = (TLRPC.TL_updateNewMessage) update; + newMessages.put(newMessage.message.id, newMessage.message); + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, newMessage.pts, -1, newMessage.pts_count)); + updatesArr.remove(a); + a--; + } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { + final TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; + newMessages.put(newMessage.message.id, newMessage.message); + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id)); + updatesArr.remove(a); + a--; } - }); + } + + for (int i = 0; i < msgObjs.size(); i++) { + final MessageObject msgObj = msgObjs.get(i); + final String originalPath = originalPaths.get(i); + final TLRPC.Message newMsgObj = msgObj.messageOwner; + final int oldId = newMsgObj.id; + final ArrayList sentMessages = new ArrayList<>(); + final String attachPath = newMsgObj.attachPath; + final long grouped_id; + + Integer id = newIds.get(newMsgObj.random_id); + if (id != null) { + TLRPC.Message message = newMessages.get(id); + if (message != null) { + sentMessages.add(message); + newMsgObj.id = message.id; + if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + grouped_id = message.grouped_id; + + Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(message.dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); + MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(message.dialog_id, value); + } + message.unread = value < message.id; + updateMediaPaths(msgObj, message, originalPath, false); + } else { + isSentError = true; + break; + } + } else { + isSentError = true; + break; + } + + if (!isSentError) { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, 1); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, oldId, newMsgObj.id, 0, false, newMsgObj.to_id.channel_id); + MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, false, 0); + AndroidUtilities.runOnUIThread(() -> { + DataQuery.getInstance(currentAccount).increasePeerRaiting(newMsgObj.dialog_id); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id); + processSentMessage(oldId); + removeFromSendingMessages(oldId); + }); + }); + } + } + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processUpdates(updates, false)); + } else { + AlertsCreator.processError(currentAccount, error, null, req); + isSentError = true; } - }, null, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter); + if (isSentError) { + for (int i = 0; i < msgObjs.size(); i++) { + TLRPC.Message newMsgObj = msgObjs.get(i).messageOwner; + MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + removeFromSendingMessages(newMsgObj.id); + } + } + }), null, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter); } private void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath) { @@ -3732,224 +3615,177 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } final TLRPC.Message newMsgObj = msgObj.messageOwner; putToSendingMessages(newMsgObj); - newMsgObj.reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (req instanceof TLRPC.TL_messages_editMessage) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - final String attachPath = newMsgObj.attachPath; + newMsgObj.reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (req instanceof TLRPC.TL_messages_editMessage) { + AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + final String attachPath = newMsgObj.attachPath; - final TLRPC.Updates updates = (TLRPC.Updates) response; - ArrayList updatesArr = ((TLRPC.Updates) response).updates; - TLRPC.Message message = null; - for (int a = 0; a < updatesArr.size(); a++) { - TLRPC.Update update = updatesArr.get(a); - if (update instanceof TLRPC.TL_updateEditMessage) { - final TLRPC.TL_updateEditMessage newMessage = (TLRPC.TL_updateEditMessage) update; - message = newMessage.message; - break; - } else if (update instanceof TLRPC.TL_updateEditChannelMessage) { - final TLRPC.TL_updateEditChannelMessage newMessage = (TLRPC.TL_updateEditChannelMessage) update; - message = newMessage.message; - break; + final TLRPC.Updates updates = (TLRPC.Updates) response; + ArrayList updatesArr = ((TLRPC.Updates) response).updates; + TLRPC.Message message = null; + for (int a = 0; a < updatesArr.size(); a++) { + TLRPC.Update update = updatesArr.get(a); + if (update instanceof TLRPC.TL_updateEditMessage) { + final TLRPC.TL_updateEditMessage newMessage = (TLRPC.TL_updateEditMessage) update; + message = newMessage.message; + break; + } else if (update instanceof TLRPC.TL_updateEditChannelMessage) { + final TLRPC.TL_updateEditChannelMessage newMessage = (TLRPC.TL_updateEditChannelMessage) update; + message = newMessage.message; + break; + } + } + if (message != null) { + ImageLoader.saveMessageThumbs(message); + updateMediaPaths(msgObj, message, originalPath, false); + } + Utilities.stageQueue.postRunnable(() -> { + MessagesController.getInstance(currentAccount).processUpdates(updates, false); + AndroidUtilities.runOnUIThread(() -> { + processSentMessage(newMsgObj.id); + removeFromSendingMessages(newMsgObj.id); + }); + }); + if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { + stopVideoService(attachPath); + } + } else { + AlertsCreator.processError(currentAccount, error, null, req); + if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { + stopVideoService(newMsgObj.attachPath); + } + removeFromSendingMessages(newMsgObj.id); + revertEditingMessageObject(msgObj); + } + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + + boolean isSentError = false; + if (error == null) { + final int oldId = newMsgObj.id; + final boolean isBroadcast = req instanceof TLRPC.TL_messages_sendBroadcast; + final ArrayList sentMessages = new ArrayList<>(); + final String attachPath = newMsgObj.attachPath; + if (response instanceof TLRPC.TL_updateShortSentMessage) { + final TLRPC.TL_updateShortSentMessage res = (TLRPC.TL_updateShortSentMessage) response; + newMsgObj.local_id = newMsgObj.id = res.id; + newMsgObj.date = res.date; + newMsgObj.entities = res.entities; + newMsgObj.out = res.out; + if (res.media != null) { + newMsgObj.media = res.media; + newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + ImageLoader.saveMessageThumbs(newMsgObj); + } + if (res.media instanceof TLRPC.TL_messageMediaGame && !TextUtils.isEmpty(res.message)) { + newMsgObj.message = res.message; + } + if (!newMsgObj.entities.isEmpty()) { + newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, res.pts, res.date, res.pts_count)); + sentMessages.add(newMsgObj); + } else if (response instanceof TLRPC.Updates) { + final TLRPC.Updates updates = (TLRPC.Updates) response; + ArrayList updatesArr = ((TLRPC.Updates) response).updates; + TLRPC.Message message = null; + for (int a = 0; a < updatesArr.size(); a++) { + TLRPC.Update update = updatesArr.get(a); + if (update instanceof TLRPC.TL_updateNewMessage) { + final TLRPC.TL_updateNewMessage newMessage = (TLRPC.TL_updateNewMessage) update; + sentMessages.add(message = newMessage.message); + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, newMessage.pts, -1, newMessage.pts_count)); + updatesArr.remove(a); + break; + } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { + final TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; + sentMessages.add(message = newMessage.message); + if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + newMessage.message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id)); + updatesArr.remove(a); + break; } - if (message != null) { - ImageLoader.saveMessageThumbs(message); - updateMediaPaths(msgObj, message, originalPath, false); + } + if (message != null) { + ImageLoader.saveMessageThumbs(message); + Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(message.dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); + MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(message.dialog_id, value); } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processUpdates(updates, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - processSentMessage(newMsgObj.id); - removeFromSendingMessages(newMsgObj.id); - } - }); + message.unread = value < message.id; + + newMsgObj.id = message.id; + updateMediaPaths(msgObj, message, originalPath, false); + } else { + isSentError = true; + } + Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(currentAccount).processUpdates(updates, false)); + } + + if (MessageObject.isLiveLocationMessage(newMsgObj)) { + LocationController.getInstance(currentAccount).addSharingLocation(newMsgObj.dialog_id, newMsgObj.id, newMsgObj.media.period, newMsgObj); + } + + if (!isSentError) { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, 1); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id, 0L); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, oldId, (isBroadcast ? oldId : newMsgObj.id), 0, false, newMsgObj.to_id.channel_id); + MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, isBroadcast, 0); + if (isBroadcast) { + ArrayList currentMessage = new ArrayList<>(); + currentMessage.add(newMsgObj); + MessagesStorage.getInstance(currentAccount).putMessages(currentMessage, true, false, false, 0); + } + AndroidUtilities.runOnUIThread(() -> { + if (isBroadcast) { + for (int a = 0; a < sentMessages.size(); a++) { + TLRPC.Message message = sentMessages.get(a); + ArrayList arr = new ArrayList<>(); + MessageObject messageObject = new MessageObject(currentAccount, message, false); + arr.add(messageObject); + MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(messageObject.getDialogId(), arr, true); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); } + DataQuery.getInstance(currentAccount).increasePeerRaiting(newMsgObj.dialog_id); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id, 0L); + processSentMessage(oldId); + removeFromSendingMessages(oldId); }); if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { stopVideoService(attachPath); } - } else { - AlertsCreator.processError(currentAccount, error, null, req); - if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { - stopVideoService(newMsgObj.attachPath); - } - removeFromSendingMessages(newMsgObj.id); - revertEditingMessageObject(msgObj); - } + }); } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - - boolean isSentError = false; - if (error == null) { - final int oldId = newMsgObj.id; - final boolean isBroadcast = req instanceof TLRPC.TL_messages_sendBroadcast; - final ArrayList sentMessages = new ArrayList<>(); - final String attachPath = newMsgObj.attachPath; - if (response instanceof TLRPC.TL_updateShortSentMessage) { - final TLRPC.TL_updateShortSentMessage res = (TLRPC.TL_updateShortSentMessage) response; - newMsgObj.local_id = newMsgObj.id = res.id; - newMsgObj.date = res.date; - newMsgObj.entities = res.entities; - newMsgObj.out = res.out; - if (res.media != null) { - newMsgObj.media = res.media; - newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; - ImageLoader.saveMessageThumbs(newMsgObj); - } - if (res.media instanceof TLRPC.TL_messageMediaGame && !TextUtils.isEmpty(res.message)) { - newMsgObj.message = res.message; - } - if (!newMsgObj.entities.isEmpty()) { - newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; - } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, res.pts, res.date, res.pts_count); - } - }); - sentMessages.add(newMsgObj); - } else if (response instanceof TLRPC.Updates) { - final TLRPC.Updates updates = (TLRPC.Updates) response; - ArrayList updatesArr = ((TLRPC.Updates) response).updates; - TLRPC.Message message = null; - for (int a = 0; a < updatesArr.size(); a++) { - TLRPC.Update update = updatesArr.get(a); - if (update instanceof TLRPC.TL_updateNewMessage) { - final TLRPC.TL_updateNewMessage newMessage = (TLRPC.TL_updateNewMessage) update; - sentMessages.add(message = newMessage.message); - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processNewDifferenceParams(-1, newMessage.pts, -1, newMessage.pts_count); - } - }); - updatesArr.remove(a); - break; - } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { - final TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; - sentMessages.add(message = newMessage.message); - if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { - newMessage.message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id); - } - }); - updatesArr.remove(a); - break; - } - } - if (message != null) { - ImageLoader.saveMessageThumbs(message); - Integer value = MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.get(message.dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, message.dialog_id); - MessagesController.getInstance(currentAccount).dialogs_read_outbox_max.put(message.dialog_id, value); - } - message.unread = value < message.id; - - newMsgObj.id = message.id; - updateMediaPaths(msgObj, message, originalPath, false); - } else { - isSentError = true; - } - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).processUpdates(updates, false); - } - }); - } - - if (MessageObject.isLiveLocationMessage(newMsgObj)) { - LocationController.getInstance(currentAccount).addSharingLocation(newMsgObj.dialog_id, newMsgObj.id, newMsgObj.media.period, newMsgObj); - } - - if (!isSentError) { - StatsController.getInstance(currentAccount).incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, 1); - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id, 0L); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - MessagesStorage.getInstance(currentAccount).updateMessageStateAndId(newMsgObj.random_id, oldId, (isBroadcast ? oldId : newMsgObj.id), 0, false, newMsgObj.to_id.channel_id); - MessagesStorage.getInstance(currentAccount).putMessages(sentMessages, true, false, isBroadcast, 0); - if (isBroadcast) { - ArrayList currentMessage = new ArrayList<>(); - currentMessage.add(newMsgObj); - MessagesStorage.getInstance(currentAccount).putMessages(currentMessage, true, false, false, 0); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (isBroadcast) { - for (int a = 0; a < sentMessages.size(); a++) { - TLRPC.Message message = sentMessages.get(a); - ArrayList arr = new ArrayList<>(); - MessageObject messageObject = new MessageObject(currentAccount, message, false); - arr.add(messageObject); - MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(messageObject.getDialogId(), arr, true); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); - } - DataQuery.getInstance(currentAccount).increasePeerRaiting(newMsgObj.dialog_id); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id, 0L); - processSentMessage(oldId); - removeFromSendingMessages(oldId); - } - }); - if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { - stopVideoService(attachPath); - } - } - }); - } - } else { - AlertsCreator.processError(currentAccount, error, null, req); - isSentError = true; - } - if (isSentError) { - MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); - processSentMessage(newMsgObj.id); - if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { - stopVideoService(newMsgObj.attachPath); - } - removeFromSendingMessages(newMsgObj.id); - } + } else { + AlertsCreator.processError(currentAccount, error, null, req); + isSentError = true; + } + if (isSentError) { + MessagesStorage.getInstance(currentAccount).markMessageAsSendError(newMsgObj); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj) || MessageObject.isRoundVideoMessage(newMsgObj) || MessageObject.isNewGifMessage(newMsgObj)) { + stopVideoService(newMsgObj.attachPath); } - }); - } - } - }, new QuickAckDelegate() { - @Override - public void run() { - final int msg_id = newMsgObj.id; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByAck, msg_id); + removeFromSendingMessages(newMsgObj.id); } }); } + }, () -> { + final int msg_id = newMsgObj.id; + AndroidUtilities.runOnUIThread(() -> { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageReceivedByAck, msg_id); + }); }, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter | (req instanceof TLRPC.TL_messages_sendMessage ? ConnectionsManager.RequestFlagNeedQuickAck : 0)); if (parentMessage != null) { @@ -4133,17 +3969,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } protected void processUnsentMessages(final ArrayList messages, final ArrayList users, final ArrayList chats, final ArrayList encryptedChats) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).putUsers(users, true); - MessagesController.getInstance(currentAccount).putChats(chats, true); - MessagesController.getInstance(currentAccount).putEncryptedChats(encryptedChats, true); - for (int a = 0; a < messages.size(); a++) { - TLRPC.Message message = messages.get(a); - MessageObject messageObject = new MessageObject(currentAccount, message, false); - retrySendMessage(messageObject, true); - } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putUsers(users, true); + MessagesController.getInstance(currentAccount).putChats(chats, true); + MessagesController.getInstance(currentAccount).putEncryptedChats(encryptedChats, true); + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + MessageObject messageObject = new MessageObject(currentAccount, message, false); + retrySendMessage(messageObject, true); } }); } @@ -4386,14 +4219,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } final TLRPC.TL_document documentFinal = document; final String pathFinal = path; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, pathFinal, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, captionFinal, entities, null, params, 0); - } + AndroidUtilities.runOnUIThread(() -> { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, pathFinal, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, captionFinal, entities, null, params, 0); } }); return true; @@ -4421,54 +4251,48 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter @UiThread public static void prepareSendingAudioDocuments(final ArrayList messageObjects, final long dialog_id, final MessageObject reply_to_msg, final MessageObject editingMessageObject) { final int currentAccount = UserConfig.selectedAccount; - new Thread(new Runnable() { - @Override - public void run() { - int size = messageObjects.size(); - for (int a = 0; a < size; a++) { - final MessageObject messageObject = messageObjects.get(a); - String originalPath = messageObject.messageOwner.attachPath; - final File f = new File(originalPath); + new Thread(() -> { + int size = messageObjects.size(); + for (int a = 0; a < size; a++) { + final MessageObject messageObject = messageObjects.get(a); + String originalPath = messageObject.messageOwner.attachPath; + final File f = new File(originalPath); - boolean isEncrypted = (int) dialog_id == 0; + boolean isEncrypted = (int) dialog_id == 0; - if (originalPath != null) { - originalPath += "audio" + f.length(); - } - - TLRPC.TL_document document = null; - if (!isEncrypted) { - document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 1 : 4); - } - if (document == null) { - document = (TLRPC.TL_document) messageObject.messageOwner.media.document; - } - - if (isEncrypted) { - int high_id = (int) (dialog_id >> 32); - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); - if (encryptedChat == null) { - return; - } - } - - final HashMap params = new HashMap<>(); - if (originalPath != null) { - params.put("originalPath", originalPath); - } - final TLRPC.TL_document documentFinal = document; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, messageObject.messageOwner.attachPath, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, messageObject.messageOwner.attachPath, dialog_id, reply_to_msg, null, null, null, params, 0); - } - } - }); + if (originalPath != null) { + originalPath += "audio" + f.length(); } + + TLRPC.TL_document document = null; + if (!isEncrypted) { + document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 1 : 4); + } + if (document == null) { + document = (TLRPC.TL_document) messageObject.messageOwner.media.document; + } + + if (isEncrypted) { + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + } + + final HashMap params = new HashMap<>(); + if (originalPath != null) { + params.put("originalPath", originalPath); + } + final TLRPC.TL_document documentFinal = document; + AndroidUtilities.runOnUIThread(() -> { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, messageObject.messageOwner.attachPath, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, messageObject.messageOwner.attachPath, dialog_id, reply_to_msg, null, null, null, params, 0); + } + }); } }).start(); } @@ -4479,40 +4303,34 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter return; } final int currentAccount = UserConfig.selectedAccount; - new Thread(new Runnable() { - @Override - public void run() { - boolean error = false; - if (paths != null) { - for (int a = 0; a < paths.size(); a++) { - if (!prepareSendingDocumentInternal(currentAccount, paths.get(a), originalPaths.get(a), null, mime, dialog_id, reply_to_msg, null, null, editingMessageObject)) { - error = true; - } + new Thread(() -> { + boolean error = false; + if (paths != null) { + for (int a = 0; a < paths.size(); a++) { + if (!prepareSendingDocumentInternal(currentAccount, paths.get(a), originalPaths.get(a), null, mime, dialog_id, reply_to_msg, null, null, editingMessageObject)) { + error = true; } } - if (uris != null) { - for (int a = 0; a < uris.size(); a++) { - if (!prepareSendingDocumentInternal(currentAccount, null, null, uris.get(a), mime, dialog_id, reply_to_msg, null, null, editingMessageObject)) { - error = true; - } + } + if (uris != null) { + for (int a = 0; a < uris.size(); a++) { + if (!prepareSendingDocumentInternal(currentAccount, null, null, uris.get(a), mime, dialog_id, reply_to_msg, null, null, editingMessageObject)) { + error = true; } } - if (inputContent != null) { - inputContent.releasePermission(); - } - if (error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - Toast toast = Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("UnsupportedAttachment", R.string.UnsupportedAttachment), Toast.LENGTH_SHORT); - toast.show(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } + } + if (inputContent != null) { + inputContent.releasePermission(); + } + if (error) { + AndroidUtilities.runOnUIThread(() -> { + try { + Toast toast = Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("UnsupportedAttachment", R.string.UnsupportedAttachment), Toast.LENGTH_SHORT); + toast.show(); + } catch (Exception e) { + FileLog.e(e); + } + }); } }).start(); } @@ -4542,230 +4360,224 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } final int currentAccount = UserConfig.selectedAccount; if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaAuto) { - new Thread(new Runnable() { - @Override - public void run() { - String finalPath = null; - TLRPC.TL_document document = null; - TLRPC.TL_photo photo = null; - TLRPC.TL_game game = null; - if (result instanceof TLRPC.TL_botInlineMediaResult) { - if (result.type.equals("game")) { - if ((int) dialog_id == 0) { - return; //doesn't work in secret chats for now - } - game = new TLRPC.TL_game(); - game.title = result.title; - game.description = result.description; - game.short_name = result.id; - game.photo = result.photo; - if (result.document instanceof TLRPC.TL_document) { - game.document = result.document; - game.flags |= 1; - } - } else if (result.document != null) { - if (result.document instanceof TLRPC.TL_document) { - document = (TLRPC.TL_document) result.document; - } - } else if (result.photo != null) { - if (result.photo instanceof TLRPC.TL_photo) { - photo = (TLRPC.TL_photo) result.photo; - } + new Thread(() -> { + String finalPath = null; + TLRPC.TL_document document = null; + TLRPC.TL_photo photo = null; + TLRPC.TL_game game = null; + if (result instanceof TLRPC.TL_botInlineMediaResult) { + if (result.type.equals("game")) { + if ((int) dialog_id == 0) { + return; //doesn't work in secret chats for now } - } else { - if (result.content != null) { - File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.content.url) + "." + ImageLoader.getHttpUrlExtension(result.content.url, "file")); - if (f.exists()) { - finalPath = f.getAbsolutePath(); - } else { - finalPath = result.content.url; - } - switch (result.type) { - case "audio": - case "voice": - case "file": - case "video": - case "sticker": - case "gif": { - document = new TLRPC.TL_document(); - document.id = 0; - document.size = 0; - document.dc_id = 0; - document.mime_type = result.content.mime_type; - document.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); - document.attributes.add(fileName); + game = new TLRPC.TL_game(); + game.title = result.title; + game.description = result.description; + game.short_name = result.id; + game.photo = result.photo; + if (result.document instanceof TLRPC.TL_document) { + game.document = result.document; + game.flags |= 1; + } + } else if (result.document != null) { + if (result.document instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) result.document; + } + } else if (result.photo != null) { + if (result.photo instanceof TLRPC.TL_photo) { + photo = (TLRPC.TL_photo) result.photo; + } + } + } else { + if (result.content != null) { + File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.content.url) + "." + ImageLoader.getHttpUrlExtension(result.content.url, "file")); + if (f.exists()) { + finalPath = f.getAbsolutePath(); + } else { + finalPath = result.content.url; + } + switch (result.type) { + case "audio": + case "voice": + case "file": + case "video": + case "sticker": + case "gif": { + document = new TLRPC.TL_document(); + document.id = 0; + document.size = 0; + document.dc_id = 0; + document.mime_type = result.content.mime_type; + document.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + document.attributes.add(fileName); - switch (result.type) { - case "gif": { - fileName.file_name = "animation.gif"; + switch (result.type) { + case "gif": { + fileName.file_name = "animation.gif"; + if (finalPath.endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } + try { + Bitmap bitmap; if (finalPath.endsWith("mp4")) { - document.mime_type = "video/mp4"; - document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + bitmap = ThumbnailUtils.createVideoThumbnail(finalPath, MediaStore.Video.Thumbnails.MINI_KIND); } else { - document.mime_type = "image/gif"; + bitmap = ImageLoader.loadBitmap(finalPath, null, 90, 90, true); } - try { - Bitmap bitmap; - if (finalPath.endsWith("mp4")) { - bitmap = ThumbnailUtils.createVideoThumbnail(finalPath, MediaStore.Video.Thumbnails.MINI_KIND); - } else { - bitmap = ImageLoader.loadBitmap(finalPath, null, 90, 90, true); - } + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); + bitmap.recycle(); + } + } catch (Throwable e) { + FileLog.e(e); + } + break; + } + case "voice": { + TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); + audio.duration = MessageObject.getInlineResultDuration(result); + audio.voice = true; + fileName.file_name = "audio.ogg"; + document.attributes.add(audio); + + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + + break; + } + case "audio": { + TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); + audio.duration = MessageObject.getInlineResultDuration(result); + audio.title = result.title; + audio.flags |= 1; + if (result.description != null) { + audio.performer = result.description; + audio.flags |= 2; + } + fileName.file_name = "audio.mp3"; + document.attributes.add(audio); + + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + + break; + } + case "file": { + int idx = result.content.mime_type.lastIndexOf('/'); + if (idx != -1) { + fileName.file_name = "file." + result.content.mime_type.substring(idx + 1); + } else { + fileName.file_name = "file"; + } + break; + } + case "video": { + fileName.file_name = "video.mp4"; + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + int wh[] = MessageObject.getInlineResultWidthAndHeight(result); + attributeVideo.w = wh[0]; + attributeVideo.h = wh[1]; + attributeVideo.duration = MessageObject.getInlineResultDuration(result); + attributeVideo.supports_streaming = true; + document.attributes.add(attributeVideo); + try { + if (result.thumb != null) { + String thumbPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb.url) + "." + ImageLoader.getHttpUrlExtension(result.thumb.url, "jpg")).getAbsolutePath(); + Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); if (bitmap != null) { document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); bitmap.recycle(); } - } catch (Throwable e) { - FileLog.e(e); } - break; - } - case "voice": { - TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); - audio.duration = MessageObject.getInlineResultDuration(result); - audio.voice = true; - fileName.file_name = "audio.ogg"; - document.attributes.add(audio); - - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; - - break; - } - case "audio": { - TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); - audio.duration = MessageObject.getInlineResultDuration(result); - audio.title = result.title; - audio.flags |= 1; - if (result.description != null) { - audio.performer = result.description; - audio.flags |= 2; - } - fileName.file_name = "audio.mp3"; - document.attributes.add(audio); - - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; - - break; - } - case "file": { - int idx = result.content.mime_type.lastIndexOf('/'); - if (idx != -1) { - fileName.file_name = "file." + result.content.mime_type.substring(idx + 1); - } else { - fileName.file_name = "file"; - } - break; - } - case "video": { - fileName.file_name = "video.mp4"; - TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); - int wh[] = MessageObject.getInlineResultWidthAndHeight(result); - attributeVideo.w = wh[0]; - attributeVideo.h = wh[1]; - attributeVideo.duration = MessageObject.getInlineResultDuration(result); - attributeVideo.supports_streaming = true; - document.attributes.add(attributeVideo); - try { - if (result.thumb != null) { - String thumbPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb.url) + "." + ImageLoader.getHttpUrlExtension(result.thumb.url, "jpg")).getAbsolutePath(); - Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); - if (bitmap != null) { - document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); - bitmap.recycle(); - } - } - } catch (Throwable e) { - FileLog.e(e); - } - break; - } - case "sticker": { - TLRPC.TL_documentAttributeSticker attributeSticker = new TLRPC.TL_documentAttributeSticker(); - attributeSticker.alt = ""; - attributeSticker.stickerset = new TLRPC.TL_inputStickerSetEmpty(); - document.attributes.add(attributeSticker); - TLRPC.TL_documentAttributeImageSize attributeImageSize = new TLRPC.TL_documentAttributeImageSize(); - int wh[] = MessageObject.getInlineResultWidthAndHeight(result); - attributeImageSize.w = wh[0]; - attributeImageSize.h = wh[1]; - document.attributes.add(attributeImageSize); - fileName.file_name = "sticker.webp"; - try { - if (result.thumb != null) { - String thumbPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb.url) + "." + ImageLoader.getHttpUrlExtension(result.thumb.url, "webp")).getAbsolutePath(); - Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); - if (bitmap != null) { - document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); - bitmap.recycle(); - } - } - } catch (Throwable e) { - FileLog.e(e); - } - break; + } catch (Throwable e) { + FileLog.e(e); } + break; } - if (fileName.file_name == null) { - fileName.file_name = "file"; - } - if (document.mime_type == null) { - document.mime_type = "application/octet-stream"; - } - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSize(); + case "sticker": { + TLRPC.TL_documentAttributeSticker attributeSticker = new TLRPC.TL_documentAttributeSticker(); + attributeSticker.alt = ""; + attributeSticker.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + document.attributes.add(attributeSticker); + TLRPC.TL_documentAttributeImageSize attributeImageSize = new TLRPC.TL_documentAttributeImageSize(); int wh[] = MessageObject.getInlineResultWidthAndHeight(result); - document.thumb.w = wh[0]; - document.thumb.h = wh[1]; - document.thumb.size = 0; - document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); - document.thumb.type = "x"; + attributeImageSize.w = wh[0]; + attributeImageSize.h = wh[1]; + document.attributes.add(attributeImageSize); + fileName.file_name = "sticker.webp"; + try { + if (result.thumb != null) { + String thumbPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb.url) + "." + ImageLoader.getHttpUrlExtension(result.thumb.url, "webp")).getAbsolutePath(); + Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); + bitmap.recycle(); + } + } + } catch (Throwable e) { + FileLog.e(e); + } + break; } - break; } - case "photo": { - if (f.exists()) { - photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(finalPath, null); - } - if (photo == null) { - photo = new TLRPC.TL_photo(); - photo.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); - int wh[] = MessageObject.getInlineResultWidthAndHeight(result); - photoSize.w = wh[0]; - photoSize.h = wh[1]; - photoSize.size = 1; - photoSize.location = new TLRPC.TL_fileLocationUnavailable(); - photoSize.type = "x"; - photo.sizes.add(photoSize); - } - break; + if (fileName.file_name == null) { + fileName.file_name = "file"; } + if (document.mime_type == null) { + document.mime_type = "application/octet-stream"; + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSize(); + int wh[] = MessageObject.getInlineResultWidthAndHeight(result); + document.thumb.w = wh[0]; + document.thumb.h = wh[1]; + document.thumb.size = 0; + document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + document.thumb.type = "x"; + } + break; + } + case "photo": { + if (f.exists()) { + photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(finalPath, null); + } + if (photo == null) { + photo = new TLRPC.TL_photo(); + photo.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); + int wh[] = MessageObject.getInlineResultWidthAndHeight(result); + photoSize.w = wh[0]; + photoSize.h = wh[1]; + photoSize.size = 1; + photoSize.location = new TLRPC.TL_fileLocationUnavailable(); + photoSize.type = "x"; + photo.sizes.add(photoSize); + } + break; } } } - final String finalPathFinal = finalPath; - final TLRPC.TL_document finalDocument = document; - final TLRPC.TL_photo finalPhoto = photo; - final TLRPC.TL_game finalGame = game; - if (params != null && result.content != null) { - params.put("originalPath", result.content.url); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (finalDocument != null) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(finalDocument, null, finalPathFinal, dialog_id, reply_to_msg, result.send_message.message, result.send_message.entities, result.send_message.reply_markup, params, 0); - } else if (finalPhoto != null) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(finalPhoto, result.content != null ? result.content.url : null, dialog_id, reply_to_msg, result.send_message.message, result.send_message.entities, result.send_message.reply_markup, params, 0); - } else if (finalGame != null) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(finalGame, dialog_id, result.send_message.reply_markup, params); - } - } - }); } + final String finalPathFinal = finalPath; + final TLRPC.TL_document finalDocument = document; + final TLRPC.TL_photo finalPhoto = photo; + final TLRPC.TL_game finalGame = game; + if (params != null && result.content != null) { + params.put("originalPath", result.content.url); + } + AndroidUtilities.runOnUIThread(() -> { + if (finalDocument != null) { + SendMessagesHelper.getInstance(currentAccount).sendMessage(finalDocument, null, finalPathFinal, dialog_id, reply_to_msg, result.send_message.message, result.send_message.entities, result.send_message.reply_markup, params, 0); + } else if (finalPhoto != null) { + SendMessagesHelper.getInstance(currentAccount).sendMessage(finalPhoto, result.content != null ? result.content.url : null, dialog_id, reply_to_msg, result.send_message.message, result.send_message.entities, result.send_message.reply_markup, params, 0); + } else if (finalGame != null) { + SendMessagesHelper.getInstance(currentAccount).sendMessage(finalGame, dialog_id, result.send_message.reply_markup, params); + } + }); }).run(); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageText) { TLRPC.WebPage webPage = null; @@ -4829,29 +4641,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter @UiThread public static void prepareSendingText(final String text, final long dialog_id) { final int currentAccount = UserConfig.selectedAccount; - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - String textFinal = getTrimmedString(text); - if (textFinal.length() != 0) { - int count = (int) Math.ceil(textFinal.length() / 4096.0f); - for (int a = 0; a < count; a++) { - String mess = textFinal.substring(a * 4096, Math.min((a + 1) * 4096, textFinal.length())); - SendMessagesHelper.getInstance(currentAccount).sendMessage(mess, dialog_id, null, null, true, null, null, null); - } - } - } - }); - } - }); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> Utilities.stageQueue.postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { + String textFinal = getTrimmedString(text); + if (textFinal.length() != 0) { + int count = (int) Math.ceil(textFinal.length() / 4096.0f); + for (int a = 0; a < count; a++) { + String mess = textFinal.substring(a * 4096, Math.min((a + 1) * 4096, textFinal.length())); + SendMessagesHelper.getInstance(currentAccount).sendMessage(mess, dialog_id, null, null, true, null, null, null); + } } - }); + }))); } @UiThread @@ -4860,41 +4659,402 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter return; } final int currentAccount = UserConfig.selectedAccount; - mediaSendQueue.postRunnable(new Runnable() { - @Override - public void run() { - long beginTime = System.currentTimeMillis(); - HashMap workers; - int count = media.size(); - boolean isEncrypted = (int) dialog_id == 0; - int enryptedLayer = 0; - if (isEncrypted) { - int high_id = (int) (dialog_id >> 32); - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); - if (encryptedChat != null) { - enryptedLayer = AndroidUtilities.getPeerLayerVersion(encryptedChat.layer); + mediaSendQueue.postRunnable(() -> { + long beginTime = System.currentTimeMillis(); + HashMap workers; + int count = media.size(); + boolean isEncrypted = (int) dialog_id == 0; + int enryptedLayer = 0; + if (isEncrypted) { + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + enryptedLayer = AndroidUtilities.getPeerLayerVersion(encryptedChat.layer); + } + } + if ((!isEncrypted || enryptedLayer >= 73) && !forceDocument && groupPhotos) { + workers = new HashMap<>(); + for (int a = 0; a < count; a++) { + final SendingMediaInfo info = media.get(a); + if (info.searchImage == null && !info.isVideo) { + String originalPath = info.path; + String tempPath = info.path; + if (tempPath == null && info.uri != null) { + tempPath = AndroidUtilities.getPath(info.uri); + originalPath = info.uri.toString(); + } + + if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) { + continue; + } else if (tempPath == null && info.uri != null) { + if (MediaController.isGif(info.uri) || MediaController.isWebp(info.uri)) { + continue; + } + } + + if (tempPath != null) { + File temp = new File(tempPath); + originalPath += temp.length() + "_" + temp.lastModified(); + } else { + originalPath = null; + } + TLRPC.TL_photo photo = null; + if (!isEncrypted && info.ttl == 0) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 0 : 3); + if (photo == null && info.uri != null) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(AndroidUtilities.getPath(info.uri), !isEncrypted ? 0 : 3); + } + } + final MediaSendPrepareWorker worker = new MediaSendPrepareWorker(); + workers.put(info, worker); + if (photo != null) { + worker.photo = photo; + } else { + worker.sync = new CountDownLatch(1); + mediaSendThreadPool.execute(() -> { + worker.photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(info.path, info.uri); + worker.sync.countDown(); + }); + } } } - if ((!isEncrypted || enryptedLayer >= 73) && !forceDocument && groupPhotos) { - workers = new HashMap<>(); - for (int a = 0; a < count; a++) { - final SendingMediaInfo info = media.get(a); - if (info.searchImage == null && !info.isVideo) { - String originalPath = info.path; - String tempPath = info.path; - if (tempPath == null && info.uri != null) { - tempPath = AndroidUtilities.getPath(info.uri); - originalPath = info.uri.toString(); - } + } else { + workers = null; + } - if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) { - continue; - } else if (tempPath == null && info.uri != null) { - if (MediaController.isGif(info.uri) || MediaController.isWebp(info.uri)) { - continue; + long groupId = 0; + long lastGroupId = 0; + + ArrayList sendAsDocuments = null; + ArrayList sendAsDocumentsOriginal = null; + ArrayList sendAsDocumentsCaptions = null; + ArrayList> sendAsDocumentsEntities = null; + + String extension = null; + int photosCount = 0; + for (int a = 0; a < count; a++) { + final SendingMediaInfo info = media.get(a); + if (groupPhotos && (!isEncrypted || enryptedLayer >= 73) && count > 1 && photosCount % 10 == 0) { + lastGroupId = groupId = Utilities.random.nextLong(); + photosCount = 0; + } + if (info.searchImage != null) { + if (info.searchImage.type == 1) { + final HashMap params = new HashMap<>(); + TLRPC.TL_document document = null; + File cacheFile; + if (info.searchImage.document instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) info.searchImage.document; + cacheFile = FileLoader.getPathToAttach(document, true); + } else { + if (!isEncrypted) { + TLRPC.Document doc = (TLRPC.Document) MessagesStorage.getInstance(currentAccount).getSentFile(info.searchImage.imageUrl, !isEncrypted ? 1 : 4); + if (doc instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) doc; } } + String md5 = Utilities.MD5(info.searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.imageUrl, "jpg"); + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + } + if (document == null) { + if (info.searchImage.localUrl != null) { + params.put("url", info.searchImage.localUrl); + } + File thumbFile = null; + document = new TLRPC.TL_document(); + document.id = 0; + document.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = "animation.gif"; + document.attributes.add(fileName); + document.size = info.searchImage.size; + document.dc_id = 0; + if (cacheFile.toString().endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } + if (cacheFile.exists()) { + thumbFile = cacheFile; + } else { + cacheFile = null; + } + if (thumbFile == null) { + String thumb = Utilities.MD5(info.searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.thumbUrl, "jpg"); + thumbFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), thumb); + if (!thumbFile.exists()) { + thumbFile = null; + } + } + if (thumbFile != null) { + try { + Bitmap bitmap; + if (thumbFile.getAbsolutePath().endsWith("mp4")) { + bitmap = ThumbnailUtils.createVideoThumbnail(thumbFile.getAbsolutePath(), MediaStore.Video.Thumbnails.MINI_KIND); + } else { + bitmap = ImageLoader.loadBitmap(thumbFile.getAbsolutePath(), null, 90, 90, true); + } + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, isEncrypted); + bitmap.recycle(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSize(); + document.thumb.w = info.searchImage.width; + document.thumb.h = info.searchImage.height; + document.thumb.size = 0; + document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + document.thumb.type = "x"; + } + } + final TLRPC.TL_document documentFinal = document; + final String originalPathFinal = info.searchImage.imageUrl; + final String pathFinal = cacheFile == null ? info.searchImage.imageUrl : cacheFile.toString(); + if (params != null && info.searchImage.imageUrl != null) { + params.put("originalPath", info.searchImage.imageUrl); + } + AndroidUtilities.runOnUIThread(() -> { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, pathFinal, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, info.caption, info.entities, null, params, 0); + } + }); + } else { + boolean needDownloadHttp = true; + TLRPC.TL_photo photo = null; + if (info.searchImage.photo instanceof TLRPC.TL_photo) { + photo = (TLRPC.TL_photo) info.searchImage.photo; + } else { + if (!isEncrypted && info.ttl == 0) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(info.searchImage.imageUrl, !isEncrypted ? 0 : 3); + } + } + if (photo == null) { + String md5 = Utilities.MD5(info.searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.imageUrl, "jpg"); + File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + if (cacheFile.exists() && cacheFile.length() != 0) { + photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(cacheFile.toString(), null); + if (photo != null) { + needDownloadHttp = false; + } + } + if (photo == null) { + md5 = Utilities.MD5(info.searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.thumbUrl, "jpg"); + cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + if (cacheFile.exists()) { + photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(cacheFile.toString(), null); + } + if (photo == null) { + photo = new TLRPC.TL_photo(); + photo.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); + photoSize.w = info.searchImage.width; + photoSize.h = info.searchImage.height; + photoSize.size = 0; + photoSize.location = new TLRPC.TL_fileLocationUnavailable(); + photoSize.type = "x"; + photo.sizes.add(photoSize); + } + } + } + if (photo != null) { + final TLRPC.TL_photo photoFinal = photo; + final boolean needDownloadHttpFinal = needDownloadHttp; + final HashMap params = new HashMap<>(); + if (info.searchImage.imageUrl != null) { + params.put("originalPath", info.searchImage.imageUrl); + } + if (groupPhotos) { + photosCount++; + params.put("groupId", "" + groupId); + if (photosCount == 10 || a == count -1) { + params.put("final", "1"); + lastGroupId = 0; + } + } + AndroidUtilities.runOnUIThread(() -> { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, photoFinal, null, null, needDownloadHttpFinal ? info.searchImage.imageUrl : null, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(photoFinal, needDownloadHttpFinal ? info.searchImage.imageUrl : null, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); + } + }); + } + } + } else { + if (info.isVideo) { + Bitmap thumb = null; + String thumbKey = null; + final VideoEditedInfo videoEditedInfo; + if (forceDocument) { + videoEditedInfo = null; + } else { + videoEditedInfo = info.videoEditedInfo != null ? info.videoEditedInfo : createCompressionSettings(info.path); + } + + if (!forceDocument && (videoEditedInfo != null || info.path.endsWith("mp4"))) { + String path = info.path; + String originalPath = info.path; + File temp = new File(originalPath); + long startTime = 0; + boolean muted = false; + + originalPath += temp.length() + "_" + temp.lastModified(); + if (videoEditedInfo != null) { + muted = videoEditedInfo.muted; + originalPath += videoEditedInfo.estimatedDuration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime + (videoEditedInfo.muted ? "_m" : ""); + if (videoEditedInfo.resultWidth != videoEditedInfo.originalWidth) { + originalPath += "_" + videoEditedInfo.resultWidth; + } + startTime = videoEditedInfo.startTime >= 0 ? videoEditedInfo.startTime : 0; + } + TLRPC.TL_document document = null; + if (!isEncrypted && info.ttl == 0) { + document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 2 : 5); + } + if (document == null) { + thumb = createVideoThumbnail(info.path, startTime); + if (thumb == null) { + thumb = ThumbnailUtils.createVideoThumbnail(info.path, MediaStore.Video.Thumbnails.MINI_KIND); + } + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); + if (thumb != null && size != null) { + thumb = null; + } + document = new TLRPC.TL_document(); + document.thumb = size; + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + } else { + document.thumb.type = "s"; + } + document.mime_type = "video/mp4"; + UserConfig.getInstance(currentAccount).saveConfig(false); + TLRPC.TL_documentAttributeVideo attributeVideo; + if (isEncrypted) { + if (enryptedLayer >= 66) { + attributeVideo = new TLRPC.TL_documentAttributeVideo(); + } else { + attributeVideo = new TLRPC.TL_documentAttributeVideo_layer65(); + } + } else { + attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.supports_streaming = true; + } + document.attributes.add(attributeVideo); + if (videoEditedInfo != null && videoEditedInfo.needConvert()) { + if (videoEditedInfo.muted) { + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + fillVideoAttribute(info.path, attributeVideo, videoEditedInfo); + videoEditedInfo.originalWidth = attributeVideo.w; + videoEditedInfo.originalHeight = attributeVideo.h; + attributeVideo.w = videoEditedInfo.resultWidth; + attributeVideo.h = videoEditedInfo.resultHeight; + } else { + attributeVideo.duration = (int) (videoEditedInfo.estimatedDuration / 1000); + if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { + attributeVideo.w = videoEditedInfo.resultHeight; + attributeVideo.h = videoEditedInfo.resultWidth; + } else { + attributeVideo.w = videoEditedInfo.resultWidth; + attributeVideo.h = videoEditedInfo.resultHeight; + } + } + document.size = (int) videoEditedInfo.estimatedSize; + String fileName = Integer.MIN_VALUE + "_" + SharedConfig.getLastLocalId() + ".mp4"; + File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + SharedConfig.saveConfig(); + path = cacheFile.getAbsolutePath(); + } else { + if (temp.exists()) { + document.size = (int) temp.length(); + } + fillVideoAttribute(info.path, attributeVideo, null); + } + } + final TLRPC.TL_document videoFinal = document; + final String originalPathFinal = originalPath; + final String finalPath = path; + final HashMap params = new HashMap<>(); + final Bitmap thumbFinal = thumb; + final String thumbKeyFinal = thumbKey; + if (originalPath != null) { + params.put("originalPath", originalPath); + } + if (!muted && groupPhotos) { + photosCount++; + params.put("groupId", "" + groupId); + if (photosCount == 10 || a == count -1) { + params.put("final", "1"); + lastGroupId = 0; + } + } + AndroidUtilities.runOnUIThread(() -> { + if (thumbFinal != null && thumbKeyFinal != null) { + ImageLoader.getInstance().putImageToCache(new BitmapDrawable(thumbFinal), thumbKeyFinal); + } + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, videoEditedInfo, videoFinal, finalPath, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(videoFinal, videoEditedInfo, finalPath, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); + } + }); + } else { + prepareSendingDocumentInternal(currentAccount, info.path, info.path, null, null, dialog_id, reply_to_msg, info.caption, info.entities, editingMessageObject); + } + } else { + String originalPath = info.path; + String tempPath = info.path; + if (tempPath == null && info.uri != null) { + tempPath = AndroidUtilities.getPath(info.uri); + originalPath = info.uri.toString(); + } + + boolean isDocument = false; + if (forceDocument) { + isDocument = true; + extension = FileLoader.getFileExtension(new File(tempPath)); + } else if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) { + if (tempPath.endsWith(".gif")) { + extension = "gif"; + } else { + extension = "webp"; + } + isDocument = true; + } else if (tempPath == null && info.uri != null) { + if (MediaController.isGif(info.uri)) { + isDocument = true; + originalPath = info.uri.toString(); + tempPath = MediaController.copyFileToCache(info.uri, "gif"); + extension = "gif"; + } else if (MediaController.isWebp(info.uri)) { + isDocument = true; + originalPath = info.uri.toString(); + tempPath = MediaController.copyFileToCache(info.uri, "webp"); + extension = "webp"; + } + } + + if (isDocument) { + if (sendAsDocuments == null) { + sendAsDocuments = new ArrayList<>(); + sendAsDocumentsOriginal = new ArrayList<>(); + sendAsDocumentsCaptions = new ArrayList<>(); + sendAsDocumentsEntities = new ArrayList<>(); + } + sendAsDocuments.add(tempPath); + sendAsDocumentsOriginal.add(originalPath); + sendAsDocumentsCaptions.add(info.caption); + sendAsDocumentsEntities.add(info.entities); + } else { if (tempPath != null) { File temp = new File(tempPath); originalPath += temp.length() + "_" + temp.lastModified(); @@ -4902,363 +5062,59 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter originalPath = null; } TLRPC.TL_photo photo = null; - if (!isEncrypted && info.ttl == 0) { - photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 0 : 3); - if (photo == null && info.uri != null) { - photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(AndroidUtilities.getPath(info.uri), !isEncrypted ? 0 : 3); - } - } - final MediaSendPrepareWorker worker = new MediaSendPrepareWorker(); - workers.put(info, worker); - if (photo != null) { - worker.photo = photo; - } else { - worker.sync = new CountDownLatch(1); - mediaSendThreadPool.execute(new Runnable() { - @Override - public void run() { - worker.photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(info.path, info.uri); - worker.sync.countDown(); - } - }); - } - } - } - } else { - workers = null; - } - - long groupId = 0; - long lastGroupId = 0; - - ArrayList sendAsDocuments = null; - ArrayList sendAsDocumentsOriginal = null; - ArrayList sendAsDocumentsCaptions = null; - ArrayList> sendAsDocumentsEntities = null; - - String extension = null; - int photosCount = 0; - for (int a = 0; a < count; a++) { - final SendingMediaInfo info = media.get(a); - if (groupPhotos && (!isEncrypted || enryptedLayer >= 73) && count > 1 && photosCount % 10 == 0) { - lastGroupId = groupId = Utilities.random.nextLong(); - photosCount = 0; - } - if (info.searchImage != null) { - if (info.searchImage.type == 1) { - final HashMap params = new HashMap<>(); - TLRPC.TL_document document = null; - File cacheFile; - if (info.searchImage.document instanceof TLRPC.TL_document) { - document = (TLRPC.TL_document) info.searchImage.document; - cacheFile = FileLoader.getPathToAttach(document, true); - } else { - if (!isEncrypted) { - TLRPC.Document doc = (TLRPC.Document) MessagesStorage.getInstance(currentAccount).getSentFile(info.searchImage.imageUrl, !isEncrypted ? 1 : 4); - if (doc instanceof TLRPC.TL_document) { - document = (TLRPC.TL_document) doc; - } - } - String md5 = Utilities.MD5(info.searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.imageUrl, "jpg"); - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); - } - if (document == null) { - if (info.searchImage.localUrl != null) { - params.put("url", info.searchImage.localUrl); - } - File thumbFile = null; - document = new TLRPC.TL_document(); - document.id = 0; - document.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); - fileName.file_name = "animation.gif"; - document.attributes.add(fileName); - document.size = info.searchImage.size; - document.dc_id = 0; - if (cacheFile.toString().endsWith("mp4")) { - document.mime_type = "video/mp4"; - document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); - } else { - document.mime_type = "image/gif"; - } - if (cacheFile.exists()) { - thumbFile = cacheFile; - } else { - cacheFile = null; - } - if (thumbFile == null) { - String thumb = Utilities.MD5(info.searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.thumbUrl, "jpg"); - thumbFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), thumb); - if (!thumbFile.exists()) { - thumbFile = null; - } - } - if (thumbFile != null) { + if (workers != null) { + MediaSendPrepareWorker worker = workers.get(info); + photo = worker.photo; + if (photo == null) { try { - Bitmap bitmap; - if (thumbFile.getAbsolutePath().endsWith("mp4")) { - bitmap = ThumbnailUtils.createVideoThumbnail(thumbFile.getAbsolutePath(), MediaStore.Video.Thumbnails.MINI_KIND); - } else { - bitmap = ImageLoader.loadBitmap(thumbFile.getAbsolutePath(), null, 90, 90, true); - } - if (bitmap != null) { - document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, isEncrypted); - bitmap.recycle(); - } + worker.sync.await(); } catch (Exception e) { FileLog.e(e); } + photo = worker.photo; } - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSize(); - document.thumb.w = info.searchImage.width; - document.thumb.h = info.searchImage.height; - document.thumb.size = 0; - document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); - document.thumb.type = "x"; - } - } - final TLRPC.TL_document documentFinal = document; - final String originalPathFinal = info.searchImage.imageUrl; - final String pathFinal = cacheFile == null ? info.searchImage.imageUrl : cacheFile.toString(); - if (params != null && info.searchImage.imageUrl != null) { - params.put("originalPath", info.searchImage.imageUrl); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, null, documentFinal, pathFinal, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, info.caption, info.entities, null, params, 0); - } - } - }); - } else { - boolean needDownloadHttp = true; - TLRPC.TL_photo photo = null; - if (info.searchImage.photo instanceof TLRPC.TL_photo) { - photo = (TLRPC.TL_photo) info.searchImage.photo; } else { if (!isEncrypted && info.ttl == 0) { - photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(info.searchImage.imageUrl, !isEncrypted ? 0 : 3); - } - } - if (photo == null) { - String md5 = Utilities.MD5(info.searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.imageUrl, "jpg"); - File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); - if (cacheFile.exists() && cacheFile.length() != 0) { - photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(cacheFile.toString(), null); - if (photo != null) { - needDownloadHttp = false; + photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 0 : 3); + if (photo == null && info.uri != null) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(AndroidUtilities.getPath(info.uri), !isEncrypted ? 0 : 3); } } if (photo == null) { - md5 = Utilities.MD5(info.searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(info.searchImage.thumbUrl, "jpg"); - cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); - if (cacheFile.exists()) { - photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(cacheFile.toString(), null); - } - if (photo == null) { - photo = new TLRPC.TL_photo(); - photo.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); - photoSize.w = info.searchImage.width; - photoSize.h = info.searchImage.height; - photoSize.size = 0; - photoSize.location = new TLRPC.TL_fileLocationUnavailable(); - photoSize.type = "x"; - photo.sizes.add(photoSize); - } + photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(info.path, info.uri); } } if (photo != null) { final TLRPC.TL_photo photoFinal = photo; - final boolean needDownloadHttpFinal = needDownloadHttp; final HashMap params = new HashMap<>(); - if (info.searchImage.imageUrl != null) { - params.put("originalPath", info.searchImage.imageUrl); + if (photo.has_stickers = info.masks != null && !info.masks.isEmpty()) { + SerializedData serializedData = new SerializedData(4 + info.masks.size() * 20); + serializedData.writeInt32(info.masks.size()); + for (int b = 0; b < info.masks.size(); b++) { + info.masks.get(b).serializeToStream(serializedData); + } + params.put("masks", Utilities.bytesToHex(serializedData.toByteArray())); + serializedData.cleanup(); + } + if (originalPath != null) { + params.put("originalPath", originalPath); } if (groupPhotos) { photosCount++; params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count -1) { + if (photosCount == 10 || a == count - 1) { params.put("final", "1"); lastGroupId = 0; } } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, photoFinal, null, null, needDownloadHttpFinal ? info.searchImage.imageUrl : null, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(photoFinal, needDownloadHttpFinal ? info.searchImage.imageUrl : null, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); - } - } - }); - } - } - } else { - if (info.isVideo) { - Bitmap thumb = null; - String thumbKey = null; - - final VideoEditedInfo videoEditedInfo; - if (forceDocument) { - videoEditedInfo = null; - } else { - videoEditedInfo = info.videoEditedInfo != null ? info.videoEditedInfo : createCompressionSettings(info.path); - } - - if (!forceDocument && (videoEditedInfo != null || info.path.endsWith("mp4"))) { - String path = info.path; - String originalPath = info.path; - File temp = new File(originalPath); - long startTime = 0; - boolean muted = false; - - originalPath += temp.length() + "_" + temp.lastModified(); - if (videoEditedInfo != null) { - muted = videoEditedInfo.muted; - originalPath += videoEditedInfo.estimatedDuration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime + (videoEditedInfo.muted ? "_m" : ""); - if (videoEditedInfo.resultWidth != videoEditedInfo.originalWidth) { - originalPath += "_" + videoEditedInfo.resultWidth; - } - startTime = videoEditedInfo.startTime >= 0 ? videoEditedInfo.startTime : 0; - } - TLRPC.TL_document document = null; - if (!isEncrypted && info.ttl == 0) { - document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 2 : 5); - } - if (document == null) { - thumb = createVideoThumbnail(info.path, startTime); - if (thumb == null) { - thumb = ThumbnailUtils.createVideoThumbnail(info.path, MediaStore.Video.Thumbnails.MINI_KIND); - } - TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); - if (thumb != null && size != null) { - thumb = null; - } - document = new TLRPC.TL_document(); - document.thumb = size; - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; + AndroidUtilities.runOnUIThread(() -> { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, photoFinal, null, null, null, params, false); } else { - document.thumb.type = "s"; - } - document.mime_type = "video/mp4"; - UserConfig.getInstance(currentAccount).saveConfig(false); - TLRPC.TL_documentAttributeVideo attributeVideo; - if (isEncrypted) { - if (enryptedLayer >= 66) { - attributeVideo = new TLRPC.TL_documentAttributeVideo(); - } else { - attributeVideo = new TLRPC.TL_documentAttributeVideo_layer65(); - } - } else { - attributeVideo = new TLRPC.TL_documentAttributeVideo(); - attributeVideo.supports_streaming = true; - } - document.attributes.add(attributeVideo); - if (videoEditedInfo != null && videoEditedInfo.needConvert()) { - if (videoEditedInfo.muted) { - document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); - fillVideoAttribute(info.path, attributeVideo, videoEditedInfo); - videoEditedInfo.originalWidth = attributeVideo.w; - videoEditedInfo.originalHeight = attributeVideo.h; - attributeVideo.w = videoEditedInfo.resultWidth; - attributeVideo.h = videoEditedInfo.resultHeight; - } else { - attributeVideo.duration = (int) (videoEditedInfo.estimatedDuration / 1000); - if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { - attributeVideo.w = videoEditedInfo.resultHeight; - attributeVideo.h = videoEditedInfo.resultWidth; - } else { - attributeVideo.w = videoEditedInfo.resultWidth; - attributeVideo.h = videoEditedInfo.resultHeight; - } - } - document.size = (int) videoEditedInfo.estimatedSize; - String fileName = Integer.MIN_VALUE + "_" + SharedConfig.getLastLocalId() + ".mp4"; - File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); - SharedConfig.saveConfig(); - path = cacheFile.getAbsolutePath(); - } else { - if (temp.exists()) { - document.size = (int) temp.length(); - } - fillVideoAttribute(info.path, attributeVideo, null); - } - } - final TLRPC.TL_document videoFinal = document; - final String originalPathFinal = originalPath; - final String finalPath = path; - final HashMap params = new HashMap<>(); - final Bitmap thumbFinal = thumb; - final String thumbKeyFinal = thumbKey; - if (originalPath != null) { - params.put("originalPath", originalPath); - } - if (!muted && groupPhotos) { - photosCount++; - params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count -1) { - params.put("final", "1"); - lastGroupId = 0; - } - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (thumbFinal != null && thumbKeyFinal != null) { - ImageLoader.getInstance().putImageToCache(new BitmapDrawable(thumbFinal), thumbKeyFinal); - } - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, videoEditedInfo, videoFinal, finalPath, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(videoFinal, videoEditedInfo, finalPath, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); - } + SendMessagesHelper.getInstance(currentAccount).sendMessage(photoFinal, null, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); } }); } else { - prepareSendingDocumentInternal(currentAccount, info.path, info.path, null, null, dialog_id, reply_to_msg, info.caption, info.entities, editingMessageObject); - } - } else { - String originalPath = info.path; - String tempPath = info.path; - if (tempPath == null && info.uri != null) { - tempPath = AndroidUtilities.getPath(info.uri); - originalPath = info.uri.toString(); - } - - boolean isDocument = false; - if (forceDocument) { - isDocument = true; - extension = FileLoader.getFileExtension(new File(tempPath)); - } else if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) { - if (tempPath.endsWith(".gif")) { - extension = "gif"; - } else { - extension = "webp"; - } - isDocument = true; - } else if (tempPath == null && info.uri != null) { - if (MediaController.isGif(info.uri)) { - isDocument = true; - originalPath = info.uri.toString(); - tempPath = MediaController.copyFileToCache(info.uri, "gif"); - extension = "gif"; - } else if (MediaController.isWebp(info.uri)) { - isDocument = true; - originalPath = info.uri.toString(); - tempPath = MediaController.copyFileToCache(info.uri, "webp"); - extension = "webp"; - } - } - - if (isDocument) { if (sendAsDocuments == null) { sendAsDocuments = new ArrayList<>(); sendAsDocumentsOriginal = new ArrayList<>(); @@ -5269,119 +5125,41 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter sendAsDocumentsOriginal.add(originalPath); sendAsDocumentsCaptions.add(info.caption); sendAsDocumentsEntities.add(info.entities); - } else { - if (tempPath != null) { - File temp = new File(tempPath); - originalPath += temp.length() + "_" + temp.lastModified(); - } else { - originalPath = null; - } - TLRPC.TL_photo photo = null; - if (workers != null) { - MediaSendPrepareWorker worker = workers.get(info); - photo = worker.photo; - if (photo == null) { - try { - worker.sync.await(); - } catch (Exception e) { - FileLog.e(e); - } - photo = worker.photo; - } - } else { - if (!isEncrypted && info.ttl == 0) { - photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 0 : 3); - if (photo == null && info.uri != null) { - photo = (TLRPC.TL_photo) MessagesStorage.getInstance(currentAccount).getSentFile(AndroidUtilities.getPath(info.uri), !isEncrypted ? 0 : 3); - } - } - if (photo == null) { - photo = SendMessagesHelper.getInstance(currentAccount).generatePhotoSizes(info.path, info.uri); - } - } - if (photo != null) { - final TLRPC.TL_photo photoFinal = photo; - final HashMap params = new HashMap<>(); - if (photo.has_stickers = info.masks != null && !info.masks.isEmpty()) { - SerializedData serializedData = new SerializedData(4 + info.masks.size() * 20); - serializedData.writeInt32(info.masks.size()); - for (int b = 0; b < info.masks.size(); b++) { - info.masks.get(b).serializeToStream(serializedData); - } - params.put("masks", Utilities.bytesToHex(serializedData.toByteArray())); - serializedData.cleanup(); - } - if (originalPath != null) { - params.put("originalPath", originalPath); - } - if (groupPhotos) { - photosCount++; - params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count - 1) { - params.put("final", "1"); - lastGroupId = 0; - } - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, photoFinal, null, null, null, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(photoFinal, null, dialog_id, reply_to_msg, info.caption, info.entities, null, params, info.ttl); - } - } - }); - } else { - if (sendAsDocuments == null) { - sendAsDocuments = new ArrayList<>(); - sendAsDocumentsOriginal = new ArrayList<>(); - sendAsDocumentsCaptions = new ArrayList<>(); - sendAsDocumentsEntities = new ArrayList<>(); - } - sendAsDocuments.add(tempPath); - sendAsDocumentsOriginal.add(originalPath); - sendAsDocumentsCaptions.add(info.caption); - sendAsDocumentsEntities.add(info.entities); - } } } } } - if (lastGroupId != 0) { - final long lastGroupIdFinal = lastGroupId; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - SendMessagesHelper instance = getInstance(currentAccount); - ArrayList arrayList = instance.delayedMessages.get("group_" + lastGroupIdFinal); - if (arrayList != null && !arrayList.isEmpty()) { + } + if (lastGroupId != 0) { + final long lastGroupIdFinal = lastGroupId; + AndroidUtilities.runOnUIThread(() -> { + SendMessagesHelper instance = getInstance(currentAccount); + ArrayList arrayList = instance.delayedMessages.get("group_" + lastGroupIdFinal); + if (arrayList != null && !arrayList.isEmpty()) { - DelayedMessage message = arrayList.get(0); + DelayedMessage message = arrayList.get(0); - MessageObject prevMessage = message.messageObjects.get(message.messageObjects.size() - 1); - message.finalGroupMessage = prevMessage.getId(); - prevMessage.messageOwner.params.put("final", "1"); + MessageObject prevMessage = message.messageObjects.get(message.messageObjects.size() - 1); + message.finalGroupMessage = prevMessage.getId(); + prevMessage.messageOwner.params.put("final", "1"); - TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); - messagesRes.messages.add(prevMessage.messageOwner); - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, message.peer, -2, 0, false); - instance.sendReadyToSendGroup(message, true, true); - } - } - }); - } - if (inputContent != null) { - inputContent.releasePermission(); - } - if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { - for (int a = 0; a < sendAsDocuments.size(); a++) { - prepareSendingDocumentInternal(currentAccount, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), null, extension, dialog_id, reply_to_msg, sendAsDocumentsCaptions.get(a), sendAsDocumentsEntities.get(a), editingMessageObject); + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + messagesRes.messages.add(prevMessage.messageOwner); + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, message.peer, -2, 0, false); + instance.sendReadyToSendGroup(message, true, true); } + }); + } + if (inputContent != null) { + inputContent.releasePermission(); + } + if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { + for (int a = 0; a < sendAsDocuments.size(); a++) { + prepareSendingDocumentInternal(currentAccount, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), null, extension, dialog_id, reply_to_msg, sendAsDocumentsCaptions.get(a), sendAsDocumentsEntities.get(a), editingMessageObject); } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("total send time = " + (System.currentTimeMillis() - beginTime)); - } + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("total send time = " + (System.currentTimeMillis() - beginTime)); } }); } @@ -5695,141 +5473,135 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter return; } final int currentAccount = UserConfig.selectedAccount; - new Thread(new Runnable() { - @Override - public void run() { + new Thread(() -> { - final VideoEditedInfo videoEditedInfo = info != null ? info : createCompressionSettings(videoPath); + final VideoEditedInfo videoEditedInfo = info != null ? info : createCompressionSettings(videoPath); - boolean isEncrypted = (int) dialog_id == 0; + boolean isEncrypted = (int) dialog_id == 0; - boolean isRound = videoEditedInfo != null && videoEditedInfo.roundVideo; - Bitmap thumb = null; - String thumbKey = null; + boolean isRound = videoEditedInfo != null && videoEditedInfo.roundVideo; + Bitmap thumb = null; + String thumbKey = null; - if (videoEditedInfo != null || videoPath.endsWith("mp4") || isRound) { - String path = videoPath; - String originalPath = videoPath; - File temp = new File(originalPath); - long startTime = 0; + if (videoEditedInfo != null || videoPath.endsWith("mp4") || isRound) { + String path = videoPath; + String originalPath = videoPath; + File temp = new File(originalPath); + long startTime = 0; - originalPath += temp.length() + "_" + temp.lastModified(); - if (videoEditedInfo != null) { - if (!isRound) { - originalPath += duration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime + (videoEditedInfo.muted ? "_m" : ""); - if (videoEditedInfo.resultWidth != videoEditedInfo.originalWidth) { - originalPath += "_" + videoEditedInfo.resultWidth; - } - } - startTime = videoEditedInfo.startTime >= 0 ? videoEditedInfo.startTime : 0; - } - TLRPC.TL_document document = null; - if (!isEncrypted && ttl == 0) { - document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 2 : 5); - } - if (document == null) { - thumb = createVideoThumbnail(videoPath, startTime); - if (thumb == null) { - thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); - } - TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); - if (thumb != null && size !=null) { - if (isRound) { - if (isEncrypted) { - Utilities.blurBitmap(thumb, 7, Build.VERSION.SDK_INT < 21 ? 0 : 1, thumb.getWidth(), thumb.getHeight(), thumb.getRowBytes()); - thumbKey = String.format(size.location.volume_id + "_" + size.location.local_id + "@%d_%d_b2", (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density), (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density)); - } else { - Utilities.blurBitmap(thumb, 3, Build.VERSION.SDK_INT < 21 ? 0 : 1, thumb.getWidth(), thumb.getHeight(), thumb.getRowBytes()); - thumbKey = String.format(size.location.volume_id + "_" + size.location.local_id + "@%d_%d_b", (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density), (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density)); - } - } else { - thumb = null; - } - } - document = new TLRPC.TL_document(); - document.thumb = size; - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; - } else { - document.thumb.type = "s"; - } - document.mime_type = "video/mp4"; - UserConfig.getInstance(currentAccount).saveConfig(false); - TLRPC.TL_documentAttributeVideo attributeVideo; - if (isEncrypted) { - int high_id = (int) (dialog_id >> 32); - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); - if (encryptedChat == null) { - return; - } - if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 66) { - attributeVideo = new TLRPC.TL_documentAttributeVideo(); - } else { - attributeVideo = new TLRPC.TL_documentAttributeVideo_layer65(); - } - } else { - attributeVideo = new TLRPC.TL_documentAttributeVideo(); - attributeVideo.supports_streaming = true; - } - attributeVideo.round_message = isRound; - document.attributes.add(attributeVideo); - if (videoEditedInfo != null && videoEditedInfo.needConvert()) { - if (videoEditedInfo.muted) { - document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); - fillVideoAttribute(videoPath, attributeVideo, videoEditedInfo); - videoEditedInfo.originalWidth = attributeVideo.w; - videoEditedInfo.originalHeight = attributeVideo.h; - attributeVideo.w = videoEditedInfo.resultWidth; - attributeVideo.h = videoEditedInfo.resultHeight; - } else { - attributeVideo.duration = (int) (duration / 1000); - if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { - attributeVideo.w = height; - attributeVideo.h = width; - } else { - attributeVideo.w = width; - attributeVideo.h = height; - } - } - document.size = (int) estimatedSize; - String fileName = Integer.MIN_VALUE + "_" + SharedConfig.getLastLocalId() + ".mp4"; - File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); - SharedConfig.saveConfig(); - path = cacheFile.getAbsolutePath(); - } else { - if (temp.exists()) { - document.size = (int) temp.length(); - } - fillVideoAttribute(videoPath, attributeVideo, null); + originalPath += temp.length() + "_" + temp.lastModified(); + if (videoEditedInfo != null) { + if (!isRound) { + originalPath += duration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime + (videoEditedInfo.muted ? "_m" : ""); + if (videoEditedInfo.resultWidth != videoEditedInfo.originalWidth) { + originalPath += "_" + videoEditedInfo.resultWidth; } } - final TLRPC.TL_document videoFinal = document; - final String originalPathFinal = originalPath; - final String finalPath = path; - final HashMap params = new HashMap<>(); - final Bitmap thumbFinal = thumb; - final String thumbKeyFinal = thumbKey; - final String captionFinal = caption != null ? caption.toString() : ""; - if (originalPath != null) { - params.put("originalPath", originalPath); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (thumbFinal != null && thumbKeyFinal != null) { - ImageLoader.getInstance().putImageToCache(new BitmapDrawable(thumbFinal), thumbKeyFinal); - } - if (editingMessageObject != null) { - SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, videoEditedInfo, videoFinal, finalPath, params, false); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage(videoFinal, videoEditedInfo, finalPath, dialog_id, reply_to_msg, captionFinal, entities, null, params, ttl); - } - } - }); - } else { - prepareSendingDocumentInternal(currentAccount, videoPath, videoPath, null, null, dialog_id, reply_to_msg, caption, entities, editingMessageObject); + startTime = videoEditedInfo.startTime >= 0 ? videoEditedInfo.startTime : 0; } + TLRPC.TL_document document = null; + if (!isEncrypted && ttl == 0) { + document = (TLRPC.TL_document) MessagesStorage.getInstance(currentAccount).getSentFile(originalPath, !isEncrypted ? 2 : 5); + } + if (document == null) { + thumb = createVideoThumbnail(videoPath, startTime); + if (thumb == null) { + thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); + } + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); + if (thumb != null && size !=null) { + if (isRound) { + if (isEncrypted) { + Utilities.blurBitmap(thumb, 7, Build.VERSION.SDK_INT < 21 ? 0 : 1, thumb.getWidth(), thumb.getHeight(), thumb.getRowBytes()); + thumbKey = String.format(size.location.volume_id + "_" + size.location.local_id + "@%d_%d_b2", (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density), (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density)); + } else { + Utilities.blurBitmap(thumb, 3, Build.VERSION.SDK_INT < 21 ? 0 : 1, thumb.getWidth(), thumb.getHeight(), thumb.getRowBytes()); + thumbKey = String.format(size.location.volume_id + "_" + size.location.local_id + "@%d_%d_b", (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density), (int) (AndroidUtilities.roundMessageSize / AndroidUtilities.density)); + } + } else { + thumb = null; + } + } + document = new TLRPC.TL_document(); + document.thumb = size; + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + } else { + document.thumb.type = "s"; + } + document.mime_type = "video/mp4"; + UserConfig.getInstance(currentAccount).saveConfig(false); + TLRPC.TL_documentAttributeVideo attributeVideo; + if (isEncrypted) { + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 66) { + attributeVideo = new TLRPC.TL_documentAttributeVideo(); + } else { + attributeVideo = new TLRPC.TL_documentAttributeVideo_layer65(); + } + } else { + attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.supports_streaming = true; + } + attributeVideo.round_message = isRound; + document.attributes.add(attributeVideo); + if (videoEditedInfo != null && videoEditedInfo.needConvert()) { + if (videoEditedInfo.muted) { + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + fillVideoAttribute(videoPath, attributeVideo, videoEditedInfo); + videoEditedInfo.originalWidth = attributeVideo.w; + videoEditedInfo.originalHeight = attributeVideo.h; + attributeVideo.w = videoEditedInfo.resultWidth; + attributeVideo.h = videoEditedInfo.resultHeight; + } else { + attributeVideo.duration = (int) (duration / 1000); + if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { + attributeVideo.w = height; + attributeVideo.h = width; + } else { + attributeVideo.w = width; + attributeVideo.h = height; + } + } + document.size = (int) estimatedSize; + String fileName = Integer.MIN_VALUE + "_" + SharedConfig.getLastLocalId() + ".mp4"; + File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + SharedConfig.saveConfig(); + path = cacheFile.getAbsolutePath(); + } else { + if (temp.exists()) { + document.size = (int) temp.length(); + } + fillVideoAttribute(videoPath, attributeVideo, null); + } + } + final TLRPC.TL_document videoFinal = document; + final String originalPathFinal = originalPath; + final String finalPath = path; + final HashMap params = new HashMap<>(); + final Bitmap thumbFinal = thumb; + final String thumbKeyFinal = thumbKey; + final String captionFinal = caption != null ? caption.toString() : ""; + if (originalPath != null) { + params.put("originalPath", originalPath); + } + AndroidUtilities.runOnUIThread(() -> { + if (thumbFinal != null && thumbKeyFinal != null) { + ImageLoader.getInstance().putImageToCache(new BitmapDrawable(thumbFinal), thumbKeyFinal); + } + if (editingMessageObject != null) { + SendMessagesHelper.getInstance(currentAccount).editMessageMedia(editingMessageObject, null, videoEditedInfo, videoFinal, finalPath, params, false); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage(videoFinal, videoEditedInfo, finalPath, dialog_id, reply_to_msg, captionFinal, entities, null, params, ttl); + } + }); + } else { + prepareSendingDocumentInternal(currentAccount, videoPath, videoPath, null, null, dialog_id, reply_to_msg, caption, entities, editingMessageObject); } }).start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index d6d46f909..6543c5b6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -16,11 +16,14 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.Base64; +import org.json.JSONObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.SerializedData; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; public class SharedConfig { @@ -46,6 +49,10 @@ public class SharedConfig { public static int suggestStickers; private static int lastLocalId = -210000; + private static String passportConfigJson = ""; + private static HashMap passportConfigMap; + public static int passportConfigHash; + private static boolean configLoaded; private static final Object sync = new Object(); private static final Object localIdSync = new Object(); @@ -135,6 +142,8 @@ public class SharedConfig { editor.putString("pushString2", pushString); editor.putString("pushAuthKey", pushAuthKey != null ? Base64.encodeToString(pushAuthKey, Base64.DEFAULT) : ""); editor.putInt("lastLocalId", lastLocalId); + editor.putString("passportConfigJson", passportConfigJson); + editor.putInt("passportConfigHash", passportConfigHash); editor.commit(); } catch (Exception e) { FileLog.e(e); @@ -172,6 +181,8 @@ public class SharedConfig { allowScreenCapture = preferences.getBoolean("allowScreenCapture", false); lastLocalId = preferences.getInt("lastLocalId", -210000); pushString = preferences.getString("pushString2", ""); + passportConfigJson = preferences.getString("passportConfigJson", ""); + passportConfigHash = preferences.getInt("passportConfigHash", 0); String authKeyString = preferences.getString("pushAuthKey", null); if (!TextUtils.isEmpty(authKeyString)) { pushAuthKey = Base64.decode(authKeyString, Base64.DEFAULT); @@ -242,6 +253,35 @@ public class SharedConfig { saveConfig(); } + public static boolean isPassportConfigLoaded() { + return passportConfigMap != null; + } + + public static void setPassportConfig(String json, int hash) { + passportConfigMap = null; + passportConfigJson = json; + passportConfigHash = hash; + saveConfig(); + getCountryLangs(); + } + + public static HashMap getCountryLangs() { + if (passportConfigMap == null) { + passportConfigMap = new HashMap<>(); + try { + JSONObject object = new JSONObject(passportConfigJson); + Iterator iter = object.keys(); + while (iter.hasNext()) { + String key = iter.next(); + passportConfigMap.put(key.toUpperCase(), object.getString(key).toUpperCase()); + } + } catch (Throwable e) { + FileLog.e(e); + } + } + return passportConfigMap; + } + public static boolean checkPasscode(String passcode) { if (passcodeSalt.length == 0) { boolean result = Utilities.MD5(passcode).equals(passcodeHash); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 2a9ec9f0a..58d5d057a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -59,6 +59,8 @@ public class Utilities { public native static String readlink(String path); public native static long getDirSize(String path, int docType); public native static void clearDir(String path, int docType, long time); + private native static int pbkdf2(byte[] password, byte[] salt, byte[] dst, int iterations); + public native static int argon2(int iterations); public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) { aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length); @@ -187,7 +189,7 @@ public class Utilities { } public static boolean isGoodGaAndGb(BigInteger g_a, BigInteger p) { - return !(g_a.compareTo(BigInteger.valueOf(1)) != 1 || g_a.compareTo(p.subtract(BigInteger.valueOf(1))) != -1); + return !(g_a.compareTo(BigInteger.valueOf(1)) <= 0 || g_a.compareTo(p.subtract(BigInteger.valueOf(1))) >= 0); } public static boolean arraysEquals(byte[] arr1, int offset1, byte[] arr2, int offset2) { @@ -255,6 +257,19 @@ public class Utilities { return new byte[32]; } + public static byte[] computeSHA256(byte[]... args) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + for (int a = 0; a < args.length; a++) { + md.update(args[a], 0, args[a].length); + } + return md.digest(); + } catch (Exception e) { + FileLog.e(e); + } + return new byte[32]; + } + public static byte[] computeSHA512(byte[] convertme) { try { MessageDigest md = MessageDigest.getInstance("SHA-512"); @@ -278,6 +293,12 @@ public class Utilities { return new byte[64]; } + public static byte[] computePBKDF2(byte[] password, byte[] salt) { + byte[] dst = new byte[64]; + Utilities.pbkdf2(password, salt, dst, 100000); + return dst; + } + public static byte[] computeSHA512(byte[] convertme, byte[] convertme2, byte[] convertme3) { try { MessageDigest md = MessageDigest.getInstance("SHA-512"); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java index b31086702..19a3d3922 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java @@ -80,6 +80,7 @@ public class VideoEncodingService extends Service implements NotificationCenter. FileLog.d("start video service"); } if (builder == null) { + NotificationsController.checkOtherNotificationsChannel(); builder = new NotificationCompat.Builder(ApplicationLoader.applicationContext); builder.setSmallIcon(android.R.drawable.stat_sys_upload); builder.setWhen(System.currentTimeMillis()); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index 034eec56b..9b29d8b24 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -40,8 +40,6 @@ import org.telegram.messenger.support.customtabsclient.shared.CustomTabsHelper; import org.telegram.messenger.support.customtabsclient.shared.ServiceConnection; import org.telegram.messenger.support.customtabsclient.shared.ServiceConnectionCallback; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; @@ -186,59 +184,45 @@ public class Browser { TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); req.message = uri.toString(); - final int reqId = ConnectionsManager.getInstance(UserConfig.selectedAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog[0].dismiss(); - } catch (Throwable ignore) { + final int reqId = ConnectionsManager.getInstance(UserConfig.selectedAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog[0].dismiss(); + } catch (Throwable ignore) { - } - progressDialog[0] = null; + } + progressDialog[0] = null; - boolean ok = false; - if (response instanceof TLRPC.TL_messageMediaWebPage) { - TLRPC.TL_messageMediaWebPage webPage = (TLRPC.TL_messageMediaWebPage) response; - if (webPage.webpage instanceof TLRPC.TL_webPage && webPage.webpage.cached_page != null) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.openArticle, webPage.webpage, uri.toString()); - ok = true; - } - } - if (!ok) { - openUrl(context, uri, allowCustom, false); - } + boolean ok = false; + if (response instanceof TLRPC.TL_messageMediaWebPage) { + TLRPC.TL_messageMediaWebPage webPage = (TLRPC.TL_messageMediaWebPage) response; + if (webPage.webpage instanceof TLRPC.TL_webPage && webPage.webpage.cached_page != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.openArticle, webPage.webpage, uri.toString()); + ok = true; + } + } + if (!ok) { + openUrl(context, uri, allowCustom, false); + } + })); + AndroidUtilities.runOnUIThread(() -> { + if (progressDialog[0] == null) { + return; + } + try { + progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog[0].setCanceledOnTouchOutside(false); + progressDialog[0].setCancelable(false); + progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(UserConfig.selectedAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); - } - }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (progressDialog[0] == null) { - return; - } - try { - progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog[0].setCanceledOnTouchOutside(false); - progressDialog[0].setCancelable(false); - progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(UserConfig.selectedAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - progressDialog[0].show(); - } catch (Exception ignore) { + progressDialog[0].show(); + } catch (Exception ignore) { - } } }, 1000); return; @@ -336,6 +320,18 @@ public class Browser { return isInternalUri(Uri.parse(url), forceBrowser); } + public static boolean isPassportUrl(String url) { + try { + url = url.toLowerCase(); + if (url.startsWith("tg:passport") || url.startsWith("tg://passport") || url.startsWith("tg:secureid") || url.contains("resolve") && url.contains("domain=telegrampassport")) { + return true; + } + } catch (Throwable ignore) { + + } + return false; + } + public static boolean isInternalUri(Uri uri, boolean forceBrowser[]) { String host = uri.getHost(); host = host != null ? host.toLowerCase() : ""; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackInfo.java deleted file mode 100755 index 96da38fd0..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/PlaybackInfo.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2; - -import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; - -/** - * Information about an ongoing playback. - */ -/* package */ final class PlaybackInfo { - - public final Timeline timeline; - public final @Nullable Object manifest; - public final MediaPeriodId periodId; - public final long startPositionUs; - public final long contentPositionUs; - public final int playbackState; - public final boolean isLoading; - public final TrackGroupArray trackGroups; - public final TrackSelectorResult trackSelectorResult; - - public volatile long positionUs; - public volatile long bufferedPositionUs; - - public PlaybackInfo( - Timeline timeline, - long startPositionUs, - TrackGroupArray trackGroups, - TrackSelectorResult trackSelectorResult) { - this( - timeline, - /* manifest= */ null, - new MediaPeriodId(/* periodIndex= */ 0), - startPositionUs, - /* contentPositionUs =*/ C.TIME_UNSET, - Player.STATE_IDLE, - /* isLoading= */ false, - trackGroups, - trackSelectorResult); - } - - public PlaybackInfo( - Timeline timeline, - @Nullable Object manifest, - MediaPeriodId periodId, - long startPositionUs, - long contentPositionUs, - int playbackState, - boolean isLoading, - TrackGroupArray trackGroups, - TrackSelectorResult trackSelectorResult) { - this.timeline = timeline; - this.manifest = manifest; - this.periodId = periodId; - this.startPositionUs = startPositionUs; - this.contentPositionUs = contentPositionUs; - this.positionUs = startPositionUs; - this.bufferedPositionUs = startPositionUs; - this.playbackState = playbackState; - this.isLoading = isLoading; - this.trackGroups = trackGroups; - this.trackSelectorResult = trackSelectorResult; - } - - public PlaybackInfo fromNewPosition( - MediaPeriodId periodId, long startPositionUs, long contentPositionUs) { - return new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - periodId.isAd() ? contentPositionUs : C.TIME_UNSET, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - } - - public PlaybackInfo copyWithPeriodIndex(int periodIndex) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId.copyWithPeriodIndex(periodIndex), - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; - } - - public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; - } - - public PlaybackInfo copyWithPlaybackState(int playbackState) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; - } - - public PlaybackInfo copyWithIsLoading(boolean isLoading) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; - } - - public PlaybackInfo copyWithTrackInfo( - TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; - } - - private static void copyMutablePositions(PlaybackInfo from, PlaybackInfo to) { - to.positionUs = from.positionUs; - to.bufferedPositionUs = from.bufferedPositionUs; - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/DefaultAnalyticsListener.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/DefaultAnalyticsListener.java deleted file mode 100755 index c21ae737e..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/analytics/DefaultAnalyticsListener.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.analytics; - -import android.net.NetworkInfo; -import android.view.Surface; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.Format; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; -import org.telegram.messenger.exoplayer2.metadata.Metadata; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; -import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import java.io.IOException; - -/** - * {@link AnalyticsListener} allowing selective overrides. All methods are implemented as no-ops. - */ -public abstract class DefaultAnalyticsListener implements AnalyticsListener { - - @Override - public void onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState) {} - - @Override - public void onTimelineChanged(EventTime eventTime, int reason) {} - - @Override - public void onPositionDiscontinuity(EventTime eventTime, int reason) {} - - @Override - public void onSeekStarted(EventTime eventTime) {} - - @Override - public void onSeekProcessed(EventTime eventTime) {} - - @Override - public void onPlaybackParametersChanged( - EventTime eventTime, PlaybackParameters playbackParameters) {} - - @Override - public void onRepeatModeChanged(EventTime eventTime, int repeatMode) {} - - @Override - public void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled) {} - - @Override - public void onLoadingChanged(EventTime eventTime, boolean isLoading) {} - - @Override - public void onPlayerError(EventTime eventTime, ExoPlaybackException error) {} - - @Override - public void onTracksChanged( - EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {} - - @Override - public void onLoadStarted( - EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} - - @Override - public void onLoadCompleted( - EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} - - @Override - public void onLoadCanceled( - EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {} - - @Override - public void onLoadError( - EventTime eventTime, - LoadEventInfo loadEventInfo, - MediaLoadData mediaLoadData, - IOException error, - boolean wasCanceled) {} - - @Override - public void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {} - - @Override - public void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) {} - - @Override - public void onMediaPeriodCreated(EventTime eventTime) {} - - @Override - public void onMediaPeriodReleased(EventTime eventTime) {} - - @Override - public void onReadingStarted(EventTime eventTime) {} - - @Override - public void onBandwidthEstimate( - EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {} - - @Override - public void onViewportSizeChange(EventTime eventTime, int width, int height) {} - - @Override - public void onNetworkTypeChanged(EventTime eventTime, NetworkInfo networkInfo) {} - - @Override - public void onMetadata(EventTime eventTime, Metadata metadata) {} - - @Override - public void onDecoderEnabled( - EventTime eventTime, int trackType, DecoderCounters decoderCounters) {} - - @Override - public void onDecoderInitialized( - EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) {} - - @Override - public void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format) {} - - @Override - public void onDecoderDisabled( - EventTime eventTime, int trackType, DecoderCounters decoderCounters) {} - - @Override - public void onAudioSessionId(EventTime eventTime, int audioSessionId) {} - - @Override - public void onAudioUnderrun( - EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {} - - @Override - public void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {} - - @Override - public void onVideoSizeChanged( - EventTime eventTime, - int width, - int height, - int unappliedRotationDegrees, - float pixelWidthHeightRatio) {} - - @Override - public void onRenderedFirstFrame(EventTime eventTime, Surface surface) {} - - @Override - public void onDrmKeysLoaded(EventTime eventTime) {} - - @Override - public void onDrmSessionManagerError(EventTime eventTime, Exception error) {} - - @Override - public void onDrmKeysRestored(EventTime eventTime) {} - - @Override - public void onDrmKeysRemoved(EventTime eventTime) {} -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionEventListener.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionEventListener.java deleted file mode 100755 index 9f6d9fb6e..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/drm/DefaultDrmSessionEventListener.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.drm; - -import android.os.Handler; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.util.Assertions; -import java.util.concurrent.CopyOnWriteArrayList; - -/** Listener of {@link DefaultDrmSessionManager} events. */ -public interface DefaultDrmSessionEventListener { - - /** Called each time keys are loaded. */ - void onDrmKeysLoaded(); - - /** - * Called when a drm error occurs. - * - *

    This method being called does not indicate that playback has failed, or that it will fail. - * The player may be able to recover from the error and continue. Hence applications should - * not implement this method to display a user visible error or initiate an application - * level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement - * such behavior). This method is called to provide the application with an opportunity to log the - * error if it wishes to do so. - * - * @param error The corresponding exception. - */ - void onDrmSessionManagerError(Exception error); - - /** Called each time offline keys are restored. */ - void onDrmKeysRestored(); - - /** Called each time offline keys are removed. */ - void onDrmKeysRemoved(); - - /** Dispatches drm events to all registered listeners. */ - final class EventDispatcher { - - private final CopyOnWriteArrayList listeners; - - /** Creates event dispatcher. */ - public EventDispatcher() { - listeners = new CopyOnWriteArrayList<>(); - } - - /** Adds listener to event dispatcher. */ - public void addListener(Handler handler, DefaultDrmSessionEventListener eventListener) { - Assertions.checkArgument(handler != null && eventListener != null); - listeners.add(new HandlerAndListener(handler, eventListener)); - } - - /** Removes listener from event dispatcher. */ - public void removeListener(DefaultDrmSessionEventListener eventListener) { - for (HandlerAndListener handlerAndListener : listeners) { - if (handlerAndListener.listener == eventListener) { - listeners.remove(handlerAndListener); - } - } - } - - /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysLoaded()}. */ - public void drmKeysLoaded() { - for (HandlerAndListener handlerAndListener : listeners) { - final DefaultDrmSessionEventListener listener = handlerAndListener.listener; - handlerAndListener.handler.post( - new Runnable() { - @Override - public void run() { - listener.onDrmKeysLoaded(); - } - }); - } - } - - /** Dispatches {@link DefaultDrmSessionEventListener#onDrmSessionManagerError(Exception)}. */ - public void drmSessionManagerError(final Exception e) { - for (HandlerAndListener handlerAndListener : listeners) { - final DefaultDrmSessionEventListener listener = handlerAndListener.listener; - handlerAndListener.handler.post( - new Runnable() { - @Override - public void run() { - listener.onDrmSessionManagerError(e); - } - }); - } - } - - /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRestored()}. */ - public void drmKeysRestored() { - for (HandlerAndListener handlerAndListener : listeners) { - final DefaultDrmSessionEventListener listener = handlerAndListener.listener; - handlerAndListener.handler.post( - new Runnable() { - @Override - public void run() { - listener.onDrmKeysRestored(); - } - }); - } - } - - /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRemoved()}. */ - public void drmKeysRemoved() { - for (HandlerAndListener handlerAndListener : listeners) { - final DefaultDrmSessionEventListener listener = handlerAndListener.listener; - handlerAndListener.handler.post( - new Runnable() { - @Override - public void run() { - listener.onDrmKeysRemoved(); - } - }); - } - } - - private static final class HandlerAndListener { - - public final Handler handler; - public final DefaultDrmSessionEventListener listener; - - public HandlerAndListener(Handler handler, DefaultDrmSessionEventListener eventListener) { - this.handler = handler; - this.listener = eventListener; - } - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacBinarySearchSeeker.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacBinarySearchSeeker.java deleted file mode 100755 index ed0bb852f..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/ext/flac/FlacBinarySearchSeeker.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.ext.flac; - -import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.extractor.Extractor; -import org.telegram.messenger.exoplayer2.extractor.ExtractorInput; -import org.telegram.messenger.exoplayer2.extractor.PositionHolder; -import org.telegram.messenger.exoplayer2.extractor.SeekMap; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.FlacStreamInfo; -import org.telegram.messenger.exoplayer2.util.Util; -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * A {@link SeekMap} implementation for FLAC stream using binary search. - * - *

    This seeker performs seeking by using binary search within the stream, until it finds the - * frame that contains the target sample. - */ -/* package */ final class FlacBinarySearchSeeker { - - /** - * When seeking within the source, if the offset is smaller than or equal to this value, the seek - * operation will be performed using a skip operation. Otherwise, the source will be reloaded at - * the new seek position. - */ - private static final long MAX_SKIP_BYTES = 256 * 1024; - - private final FlacStreamInfo streamInfo; - private final FlacBinarySearchSeekMap seekMap; - private final FlacDecoderJni decoderJni; - - private final long firstFramePosition; - private final long inputLength; - private final long approxBytesPerFrame; - - private @Nullable SeekOperationParams pendingSeekOperationParams; - - public FlacBinarySearchSeeker( - FlacStreamInfo streamInfo, - long firstFramePosition, - long inputLength, - FlacDecoderJni decoderJni) { - this.streamInfo = Assertions.checkNotNull(streamInfo); - this.decoderJni = Assertions.checkNotNull(decoderJni); - this.firstFramePosition = firstFramePosition; - this.inputLength = inputLength; - this.approxBytesPerFrame = streamInfo.getApproxBytesPerFrame(); - - pendingSeekOperationParams = null; - seekMap = - new FlacBinarySearchSeekMap( - streamInfo, - firstFramePosition, - inputLength, - streamInfo.durationUs(), - approxBytesPerFrame); - } - - /** Returns the seek map for the wrapped FLAC stream. */ - public SeekMap getSeekMap() { - return seekMap; - } - - /** Sets the target time in microseconds within the stream to seek to. */ - public void setSeekTargetUs(long timeUs) { - if (pendingSeekOperationParams != null && pendingSeekOperationParams.seekTimeUs == timeUs) { - return; - } - - pendingSeekOperationParams = - new SeekOperationParams( - timeUs, - streamInfo.getSampleIndex(timeUs), - /* floorSample= */ 0, - /* ceilingSample= */ streamInfo.totalSamples, - /* floorPosition= */ firstFramePosition, - /* ceilingPosition= */ inputLength, - approxBytesPerFrame); - } - - /** Returns whether the last operation set by {@link #setSeekTargetUs(long)} is still pending. */ - public boolean hasPendingSeek() { - return pendingSeekOperationParams != null; - } - - /** - * Continues to handle the pending seek operation. Returns one of the {@code RESULT_} values from - * {@link Extractor}. - * - * @param input The {@link ExtractorInput} from which data should be read. - * @param seekPositionHolder If {@link Extractor#RESULT_SEEK} is returned, this holder is updated - * to hold the position of the required seek. - * @param outputBuffer If {@link Extractor#RESULT_CONTINUE} is returned, this byte buffer maybe - * updated to hold the extracted frame that contains the target sample. The caller needs to - * check the byte buffer limit to see if an extracted frame is available. - * @return One of the {@code RESULT_} values defined in {@link Extractor}. - * @throws IOException If an error occurred reading from the input. - * @throws InterruptedException If the thread was interrupted. - */ - public int handlePendingSeek( - ExtractorInput input, PositionHolder seekPositionHolder, ByteBuffer outputBuffer) - throws InterruptedException, IOException { - outputBuffer.position(0); - outputBuffer.limit(0); - while (true) { - long floorPosition = pendingSeekOperationParams.floorPosition; - long ceilingPosition = pendingSeekOperationParams.ceilingPosition; - long searchPosition = pendingSeekOperationParams.nextSearchPosition; - - // streamInfo may not contain minFrameSize, in which case this value will be 0. - int minFrameSize = Math.max(1, streamInfo.minFrameSize); - if (floorPosition + minFrameSize >= ceilingPosition) { - // The seeking range is too small for more than 1 frame, so we can just continue from - // the floor position. - pendingSeekOperationParams = null; - decoderJni.reset(floorPosition); - return seekToPosition(input, floorPosition, seekPositionHolder); - } - - if (!skipInputUntilPosition(input, searchPosition)) { - return seekToPosition(input, searchPosition, seekPositionHolder); - } - - decoderJni.reset(searchPosition); - try { - decoderJni.decodeSampleWithBacktrackPosition( - outputBuffer, /* retryPosition= */ searchPosition); - } catch (FlacDecoderJni.FlacFrameDecodeException e) { - // For some reasons, the extractor can't find a frame mid-stream. - // Stop the seeking and let it re-try playing at the last search position. - pendingSeekOperationParams = null; - throw new IOException("Cannot read frame at position " + searchPosition, e); - } - if (outputBuffer.limit() == 0) { - return Extractor.RESULT_END_OF_INPUT; - } - - long lastFrameSampleIndex = decoderJni.getLastFrameFirstSampleIndex(); - long nextFrameSampleIndex = decoderJni.getNextFrameFirstSampleIndex(); - long nextFrameSamplePosition = decoderJni.getDecodePosition(); - - boolean targetSampleInLastFrame = - lastFrameSampleIndex <= pendingSeekOperationParams.targetSample - && nextFrameSampleIndex > pendingSeekOperationParams.targetSample; - - if (targetSampleInLastFrame) { - pendingSeekOperationParams = null; - return Extractor.RESULT_CONTINUE; - } - - if (nextFrameSampleIndex <= pendingSeekOperationParams.targetSample) { - pendingSeekOperationParams.updateSeekFloor(nextFrameSampleIndex, nextFrameSamplePosition); - } else { - pendingSeekOperationParams.updateSeekCeiling(lastFrameSampleIndex, searchPosition); - } - } - } - - private boolean skipInputUntilPosition(ExtractorInput input, long position) - throws IOException, InterruptedException { - long bytesToSkip = position - input.getPosition(); - if (bytesToSkip >= 0 && bytesToSkip <= MAX_SKIP_BYTES) { - input.skipFully((int) bytesToSkip); - return true; - } - return false; - } - - private int seekToPosition( - ExtractorInput input, long position, PositionHolder seekPositionHolder) { - if (position == input.getPosition()) { - return Extractor.RESULT_CONTINUE; - } else { - seekPositionHolder.position = position; - return Extractor.RESULT_SEEK; - } - } - - /** - * Contains parameters for a pending seek operation by {@link FlacBinarySearchSeeker}. - * - *

    This class holds parameters for a binary-search for the {@code targetSample} in the range - * [floorPosition, ceilingPosition). - */ - private static final class SeekOperationParams { - private final long seekTimeUs; - private final long targetSample; - private final long approxBytesPerFrame; - private long floorSample; - private long ceilingSample; - private long floorPosition; - private long ceilingPosition; - private long nextSearchPosition; - - private SeekOperationParams( - long seekTimeUs, - long targetSample, - long floorSample, - long ceilingSample, - long floorPosition, - long ceilingPosition, - long approxBytesPerFrame) { - this.seekTimeUs = seekTimeUs; - this.floorSample = floorSample; - this.ceilingSample = ceilingSample; - this.floorPosition = floorPosition; - this.ceilingPosition = ceilingPosition; - this.targetSample = targetSample; - this.approxBytesPerFrame = approxBytesPerFrame; - updateNextSearchPosition(); - } - - /** Updates the floor constraints (inclusive) of the seek operation. */ - private void updateSeekFloor(long floorSample, long floorPosition) { - this.floorSample = floorSample; - this.floorPosition = floorPosition; - updateNextSearchPosition(); - } - - /** Updates the ceiling constraints (exclusive) of the seek operation. */ - private void updateSeekCeiling(long ceilingSample, long ceilingPosition) { - this.ceilingSample = ceilingSample; - this.ceilingPosition = ceilingPosition; - updateNextSearchPosition(); - } - - private void updateNextSearchPosition() { - this.nextSearchPosition = - getNextSearchPosition( - targetSample, - floorSample, - ceilingSample, - floorPosition, - ceilingPosition, - approxBytesPerFrame); - } - - /** - * Returns the next position in FLAC stream to search for target sample, given [floorPosition, - * ceilingPosition). - */ - private static long getNextSearchPosition( - long targetSample, - long floorSample, - long ceilingSample, - long floorPosition, - long ceilingPosition, - long approxBytesPerFrame) { - if (floorPosition + 1 >= ceilingPosition || floorSample + 1 >= ceilingSample) { - return floorPosition; - } - long samplesToSkip = targetSample - floorSample; - long estimatedBytesPerSample = - Math.max(1, (ceilingPosition - floorPosition) / (ceilingSample - floorSample)); - // In the stream, the samples are accessed in a group of frame. Given a stream position, the - // seeker will be able to find the first frame following that position. - // Hence, if our target sample is in the middle of a frame, and our estimate position is - // correct, or very near the actual sample position, the seeker will keep accessing the next - // frame, rather than the frame that contains the target sample. - // Moreover, it's better to under-estimate rather than over-estimate, because the extractor - // input can skip forward easily, but cannot rewind easily (it may require a new connection - // to be made). - // Therefore, we should reduce the estimated position by some amount, so it will converge to - // the correct frame earlier. - long bytesToSkip = samplesToSkip * estimatedBytesPerSample; - long confidenceInterval = bytesToSkip / 20; - - long estimatedFramePosition = floorPosition + bytesToSkip - (approxBytesPerFrame - 1); - long estimatedPosition = estimatedFramePosition - confidenceInterval; - - return Util.constrainValue(estimatedPosition, floorPosition, ceilingPosition - 1); - } - } - - /** - * A {@link SeekMap} implementation that returns the estimated byte location from {@link - * SeekOperationParams#getNextSearchPosition(long, long, long, long, long, long)} for each {@link - * #getSeekPoints(long)} query. - */ - private static final class FlacBinarySearchSeekMap implements SeekMap { - private final FlacStreamInfo streamInfo; - private final long firstFramePosition; - private final long inputLength; - private final long approxBytesPerFrame; - private final long durationUs; - - private FlacBinarySearchSeekMap( - FlacStreamInfo streamInfo, - long firstFramePosition, - long inputLength, - long durationUs, - long approxBytesPerFrame) { - this.streamInfo = streamInfo; - this.firstFramePosition = firstFramePosition; - this.inputLength = inputLength; - this.approxBytesPerFrame = approxBytesPerFrame; - this.durationUs = durationUs; - } - - @Override - public boolean isSeekable() { - return true; - } - - @Override - public SeekPoints getSeekPoints(long timeUs) { - long nextSearchPosition = - SeekOperationParams.getNextSearchPosition( - streamInfo.getSampleIndex(timeUs), - /* floorSample= */ 0, - /* ceilingSample= */ streamInfo.totalSamples, - /* floorPosition= */ firstFramePosition, - /* ceilingPosition= */ inputLength, - approxBytesPerFrame); - return new SeekPoints(new SeekPoint(timeUs, nextSearchPosition)); - } - - @Override - public long getDurationUs() { - return durationUs; - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java deleted file mode 100755 index b0dc52c90..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.extractor.mp3; - -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.extractor.MpegAudioHeader; -import org.telegram.messenger.exoplayer2.extractor.SeekPoint; -import org.telegram.messenger.exoplayer2.util.Util; - -/** - * MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate. - */ -/* package */ final class ConstantBitrateSeeker implements Mp3Extractor.Seeker { - - private static final int BITS_PER_BYTE = 8; - - private final long firstFramePosition; - private final int frameSize; - private final long dataSize; - private final int bitrate; - private final long durationUs; - - /** - * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown. - * @param firstFramePosition The position of the first frame in the stream. - * @param mpegAudioHeader The MPEG audio header associated with the first frame. - */ - public ConstantBitrateSeeker(long inputLength, long firstFramePosition, - MpegAudioHeader mpegAudioHeader) { - this.firstFramePosition = firstFramePosition; - this.frameSize = mpegAudioHeader.frameSize; - this.bitrate = mpegAudioHeader.bitrate; - if (inputLength == C.LENGTH_UNSET) { - dataSize = C.LENGTH_UNSET; - durationUs = C.TIME_UNSET; - } else { - dataSize = inputLength - firstFramePosition; - durationUs = getTimeUs(inputLength); - } - } - - @Override - public boolean isSeekable() { - return dataSize != C.LENGTH_UNSET; - } - - @Override - public SeekPoints getSeekPoints(long timeUs) { - if (dataSize == C.LENGTH_UNSET) { - return new SeekPoints(new SeekPoint(0, firstFramePosition)); - } - long positionOffset = (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE); - // Constrain to nearest preceding frame offset. - positionOffset = (positionOffset / frameSize) * frameSize; - positionOffset = Util.constrainValue(positionOffset, 0, dataSize - frameSize); - long seekPosition = firstFramePosition + positionOffset; - long seekTimeUs = getTimeUs(seekPosition); - SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekPosition); - if (seekTimeUs >= timeUs || positionOffset == dataSize - frameSize) { - return new SeekPoints(seekPoint); - } else { - long secondSeekPosition = seekPosition + frameSize; - long secondSeekTimeUs = getTimeUs(secondSeekPosition); - SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition); - return new SeekPoints(seekPoint, secondSeekPoint); - } - } - - @Override - public long getTimeUs(long position) { - return (Math.max(0, position - firstFramePosition) * C.MICROS_PER_SECOND * BITS_PER_BYTE) - / bitrate; - } - - @Override - public long getDurationUs() { - return durationUs; - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecSelector.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecSelector.java deleted file mode 100755 index 87a03fe1b..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/mediacodec/MediaCodecSelector.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.mediacodec; - -import android.media.MediaCodec; -import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; - -/** - * Selector of {@link MediaCodec} instances. - */ -public interface MediaCodecSelector { - - /** - * Default implementation of {@link MediaCodecSelector}. - */ - MediaCodecSelector DEFAULT = new MediaCodecSelector() { - - @Override - public MediaCodecInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder) - throws DecoderQueryException { - return MediaCodecUtil.getDecoderInfo(mimeType, requiresSecureDecoder); - } - - @Override - public MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException { - return MediaCodecUtil.getPassthroughDecoderInfo(); - } - - }; - - /** - * Selects a decoder to instantiate for a given mime type. - * - * @param mimeType The mime type for which a decoder is required. - * @param requiresSecureDecoder Whether a secure decoder is required. - * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. - * @throws DecoderQueryException Thrown if there was an error querying decoders. - */ - MediaCodecInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder) - throws DecoderQueryException; - - /** - * Selects a decoder to instantiate for audio passthrough. - * - * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. - * @throws DecoderQueryException Thrown if there was an error querying decoders. - */ - MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException; - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RepresentationKey.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RepresentationKey.java deleted file mode 100755 index 0442354cc..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/dash/manifest/RepresentationKey.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.source.dash.manifest; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -/** Uniquely identifies a {@link Representation} in a {@link DashManifest}. */ -public final class RepresentationKey implements Comparable { - - public final int periodIndex; - public final int adaptationSetIndex; - public final int representationIndex; - - public RepresentationKey(int periodIndex, int adaptationSetIndex, int representationIndex) { - this.periodIndex = periodIndex; - this.adaptationSetIndex = adaptationSetIndex; - this.representationIndex = representationIndex; - } - - @Override - public String toString() { - return periodIndex + "." + adaptationSetIndex + "." + representationIndex; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RepresentationKey that = (RepresentationKey) o; - return periodIndex == that.periodIndex - && adaptationSetIndex == that.adaptationSetIndex - && representationIndex == that.representationIndex; - } - - @Override - public int hashCode() { - int result = periodIndex; - result = 31 * result + adaptationSetIndex; - result = 31 * result + representationIndex; - return result; - } - - // Comparable implementation. - - @Override - public int compareTo(@NonNull RepresentationKey o) { - int result = periodIndex - o.periodIndex; - if (result == 0) { - result = adaptationSetIndex - o.adaptationSetIndex; - if (result == 0) { - result = representationIndex - o.representationIndex; - } - } - return result; - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadAction.java deleted file mode 100755 index 690202f97..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/offline/HlsDownloadAction.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.source.hls.offline; - -import android.net.Uri; -import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.offline.DownloadAction; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloadAction; -import org.telegram.messenger.exoplayer2.source.hls.playlist.RenditionKey; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.List; - -/** An action to download or remove downloaded HLS streams. */ -public final class HlsDownloadAction extends SegmentDownloadAction { - - private static final String TYPE = "hls"; - private static final int VERSION = 0; - - public static final Deserializer DESERIALIZER = - new SegmentDownloadActionDeserializer(TYPE, VERSION) { - - @Override - protected RenditionKey readKey(DataInputStream input) throws IOException { - int renditionGroup = input.readInt(); - int trackIndex = input.readInt(); - return new RenditionKey(renditionGroup, trackIndex); - } - - @Override - protected DownloadAction createDownloadAction( - Uri uri, boolean isRemoveAction, byte[] data, List keys) { - return new HlsDownloadAction(uri, isRemoveAction, data, keys); - } - }; - - /** - * @param uri The HLS playlist URI. - * @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded. - * @param data Optional custom data for this action. - * @param keys Keys of renditions to be downloaded. If empty, all renditions are downloaded. If - * {@code removeAction} is true, {@code keys} must empty. - */ - public HlsDownloadAction( - Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { - super(TYPE, VERSION, uri, isRemoveAction, data, keys); - } - - @Override - protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { - return new HlsDownloader(uri, keys, constructorHelper); - } - - @Override - protected void writeKey(DataOutputStream output, RenditionKey key) throws IOException { - output.writeInt(key.type); - output.writeInt(key.trackIndex); - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/RenditionKey.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/RenditionKey.java deleted file mode 100755 index b87a4afaf..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/hls/playlist/RenditionKey.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.source.hls.playlist; - -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** Uniquely identifies a rendition in an {@link HlsMasterPlaylist}. */ -public final class RenditionKey implements Comparable { - - /** Types of rendition. */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({TYPE_VARIANT, TYPE_AUDIO, TYPE_SUBTITLE}) - public @interface Type {} - - public static final int TYPE_VARIANT = 0; - public static final int TYPE_AUDIO = 1; - public static final int TYPE_SUBTITLE = 2; - - public final @Type int type; - public final int trackIndex; - - public RenditionKey(@Type int type, int trackIndex) { - this.type = type; - this.trackIndex = trackIndex; - } - - @Override - public String toString() { - return type + "." + trackIndex; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RenditionKey that = (RenditionKey) o; - return type == that.type && trackIndex == that.trackIndex; - } - - @Override - public int hashCode() { - int result = type; - result = 31 * result + trackIndex; - return result; - } - - // Comparable implementation. - - @Override - public int compareTo(@NonNull RenditionKey other) { - int result = type - other.type; - if (result == 0) { - result = trackIndex - other.trackIndex; - } - return result; - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java deleted file mode 100755 index 198ed6837..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.source.smoothstreaming.offline; - -import android.net.Uri; -import android.support.annotation.Nullable; -import org.telegram.messenger.exoplayer2.offline.DownloadAction; -import org.telegram.messenger.exoplayer2.offline.DownloaderConstructorHelper; -import org.telegram.messenger.exoplayer2.offline.SegmentDownloadAction; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.manifest.StreamKey; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.List; - -/** An action to download or remove downloaded SmoothStreaming streams. */ -public final class SsDownloadAction extends SegmentDownloadAction { - - private static final String TYPE = "ss"; - private static final int VERSION = 0; - - public static final Deserializer DESERIALIZER = - new SegmentDownloadActionDeserializer(TYPE, VERSION) { - - @Override - protected StreamKey readKey(DataInputStream input) throws IOException { - return new StreamKey(input.readInt(), input.readInt()); - } - - @Override - protected DownloadAction createDownloadAction( - Uri uri, boolean isRemoveAction, byte[] data, List keys) { - return new SsDownloadAction(uri, isRemoveAction, data, keys); - } - }; - - /** - * @param uri The SmoothStreaming manifest URI. - * @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded. - * @param data Optional custom data for this action. - * @param keys Keys of streams to be downloaded. If empty, all streams are downloaded. If {@code - * removeAction} is true, {@code keys} must be empty. - */ - public SsDownloadAction( - Uri uri, boolean isRemoveAction, @Nullable byte[] data, List keys) { - super(TYPE, VERSION, uri, isRemoveAction, data, keys); - } - - @Override - protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { - return new SsDownloader(uri, keys, constructorHelper); - } - - @Override - protected void writeKey(DataOutputStream output, StreamKey key) throws IOException { - output.writeInt(key.streamElementIndex); - output.writeInt(key.trackIndex); - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelector.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelector.java deleted file mode 100755 index fce6ce519..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/trackselection/TrackSelector.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.trackselection; - -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.Renderer; -import org.telegram.messenger.exoplayer2.RendererCapabilities; -import org.telegram.messenger.exoplayer2.RendererConfiguration; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; - -/** - * The component of an {@link ExoPlayer} responsible for selecting tracks to be consumed by each of - * the player's {@link Renderer}s. The {@link DefaultTrackSelector} implementation should be - * suitable for most use cases. - * - *

    Interactions with the player

    - * The following interactions occur between the player and its track selector during playback. - *

    - *

      - *
    • When the player is created it will initialize the track selector by calling - * {@link #init(InvalidationListener)}.
    • - *
    • When the player needs to make a track selection it will call - * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the - * start of playback, when the player starts to buffer a new period of the media being played, - * and when the track selector invalidates its previous selections.
    • - *
    • The player may perform a track selection well in advance of the selected tracks becoming - * active, where active is defined to mean that the renderers are actually consuming media - * corresponding to the selection that was made. For example when playing media containing - * multiple periods, the track selection for a period is made when the player starts to buffer - * that period. Hence if the player's buffering policy is to maintain a 30 second buffer, the - * selection will occur approximately 30 seconds in advance of it becoming active. In fact the - * selection may never become active, for example if the user seeks to some other period of the - * media during the 30 second gap. The player indicates to the track selector when a selection - * it has previously made becomes active by calling {@link #onSelectionActivated(Object)}.
    • - *
    • If the track selector wishes to indicate to the player that selections it has previously - * made are invalid, it can do so by calling - * {@link InvalidationListener#onTrackSelectionsInvalidated()} on the - * {@link InvalidationListener} that was passed to {@link #init(InvalidationListener)}. A - * track selector may wish to do this if its configuration has changed, for example if it now - * wishes to prefer audio tracks in a particular language. This will trigger the player to make - * new track selections. Note that the player will have to re-buffer in the case that the new - * track selection for the currently playing period differs from the one that was invalidated. - *
    • - *
    - * - *

    Renderer configuration

    - * The {@link TrackSelectorResult} returned by - * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} contains not only - * {@link TrackSelection}s for each renderer, but also {@link RendererConfiguration}s defining - * configuration parameters that the renderers should apply when consuming the corresponding media. - * Whilst it may seem counter-intuitive for a track selector to also specify renderer configuration - * information, in practice the two are tightly bound together. It may only be possible to play a - * certain combination tracks if the renderers are configured in a particular way. Equally, it may - * only be possible to configure renderers in a particular way if certain tracks are selected. Hence - * it makes sense to determined the track selection and corresponding renderer configurations in a - * single step. - * - *

    Threading model

    - * All calls made by the player into the track selector are on the player's internal playback - * thread. The track selector may call {@link InvalidationListener#onTrackSelectionsInvalidated()} - * from any thread. - */ -public abstract class TrackSelector { - - /** - * Notified when selections previously made by a {@link TrackSelector} are no longer valid. - */ - public interface InvalidationListener { - - /** - * Called by a {@link TrackSelector} to indicate that selections it has previously made are no - * longer valid. May be called from any thread. - */ - void onTrackSelectionsInvalidated(); - - } - - private InvalidationListener listener; - - /** - * Called by the player to initialize the selector. - * - * @param listener An invalidation listener that the selector can call to indicate that selections - * it has previously made are no longer valid. - */ - public final void init(InvalidationListener listener) { - this.listener = listener; - } - - /** - * Called by the player to perform a track selection. - * - * @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which tracks - * are to be selected. - * @param trackGroups The available track groups. - * @return A {@link TrackSelectorResult} describing the track selections. - * @throws ExoPlaybackException If an error occurs selecting tracks. - */ - public abstract TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, - TrackGroupArray trackGroups) throws ExoPlaybackException; - - /** - * Called by the player when a {@link TrackSelectorResult} previously generated by - * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} is activated. - * - * @param info The value of {@link TrackSelectorResult#info} in the activated selection. - */ - public abstract void onSelectionActivated(Object info); - - /** - * Calls {@link InvalidationListener#onTrackSelectionsInvalidated()} to invalidate all previously - * generated track selections. - */ - protected final void invalidate() { - if (listener != null) { - listener.onTrackSelectionsInvalidated(); - } - } - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TransferListener.java b/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TransferListener.java deleted file mode 100755 index c641127d3..000000000 --- a/TMessagesProj/src/main/java/org/telegram/messenger/exoplayer2/upstream/TransferListener.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.telegram.messenger.exoplayer2.upstream; - -/** - * A listener of data transfer events. - */ -public interface TransferListener { - - /** - * Called when a transfer starts. - * - * @param source The source performing the transfer. - * @param dataSpec Describes the data being transferred. - */ - void onTransferStart(S source, DataSpec dataSpec); - - /** - * Called incrementally during a transfer. - * - * @param source The source performing the transfer. - * @param bytesTransferred The number of bytes transferred since the previous call to this - * method (or if the first call, since the transfer was started). - */ - void onBytesTransferred(S source, int bytesTransferred); - - /** - * Called when a transfer ends. - * - * @param source The source performing the transfer. - */ - void onTransferEnd(S source); - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/EncryptedFileDataSource.java b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/EncryptedFileDataSource.java index 3c06e7ed7..d0449d28f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/EncryptedFileDataSource.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/EncryptedFileDataSource.java @@ -9,13 +9,15 @@ package org.telegram.messenger.secretmedia; import android.net.Uri; +import android.support.annotation.Nullable; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; import org.telegram.messenger.FileLoader; import org.telegram.messenger.Utilities; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.TransferListener; import java.io.EOFException; import java.io.File; @@ -32,10 +34,12 @@ public final class EncryptedFileDataSource implements DataSource { } - private final TransferListener listener; + private final TransferListener listener; private RandomAccessFile file; private Uri uri; + private @Nullable + DataSpec dataSpec; private long bytesRemaining; private boolean opened; private byte[] key = new byte[32]; @@ -46,13 +50,14 @@ public final class EncryptedFileDataSource implements DataSource { this(null); } - public EncryptedFileDataSource(TransferListener listener) { + public EncryptedFileDataSource(TransferListener listener) { this.listener = listener; } @Override public long open(DataSpec dataSpec) throws EncryptedFileDataSourceException { try { + this.dataSpec = dataSpec; uri = dataSpec.uri; File path = new File(dataSpec.uri.getPath()); String name = path.getName(); @@ -75,7 +80,7 @@ public final class EncryptedFileDataSource implements DataSource { opened = true; if (listener != null) { - listener.onTransferStart(this, dataSpec); + listener.onTransferStart(this, dataSpec, false); } return bytesRemaining; @@ -100,7 +105,7 @@ public final class EncryptedFileDataSource implements DataSource { if (bytesRead > 0) { bytesRemaining -= bytesRead; if (listener != null) { - listener.onBytesTransferred(this, bytesRead); + listener.onBytesTransferred(this, dataSpec, false, bytesRead); } } @@ -128,7 +133,7 @@ public final class EncryptedFileDataSource implements DataSource { if (opened) { opened = false; if (listener != null) { - listener.onTransferEnd(this); + listener.onTransferEnd(this, dataSpec, false); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSource.java b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSource.java index 700a8b4d2..589680ec6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSource.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSource.java @@ -11,16 +11,17 @@ package org.telegram.messenger.secretmedia; import android.content.Context; import android.net.Uri; +import com.google.android.exoplayer2.upstream.AssetDataSource; +import com.google.android.exoplayer2.upstream.ContentDataSource; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; +import com.google.android.exoplayer2.upstream.FileDataSource; +import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; + import org.telegram.messenger.FileLoader; -import org.telegram.messenger.exoplayer2.upstream.AssetDataSource; -import org.telegram.messenger.exoplayer2.upstream.ContentDataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DataSpec; -import org.telegram.messenger.exoplayer2.upstream.DefaultHttpDataSource; -import org.telegram.messenger.exoplayer2.upstream.FileDataSource; -import org.telegram.messenger.exoplayer2.upstream.TransferListener; -import org.telegram.messenger.exoplayer2.util.Assertions; -import org.telegram.messenger.exoplayer2.util.Util; import java.io.IOException; @@ -36,7 +37,7 @@ public final class ExtendedDefaultDataSource implements DataSource { private final DataSource contentDataSource; private DataSource dataSource; - private TransferListener listener; + private TransferListener listener; /** * Constructs a new instance, optionally configured to follow cross-protocol redirects. @@ -47,7 +48,7 @@ public final class ExtendedDefaultDataSource implements DataSource { * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled when fetching remote data. */ - public ExtendedDefaultDataSource(Context context, TransferListener listener, + public ExtendedDefaultDataSource(Context context, TransferListener listener, String userAgent, boolean allowCrossProtocolRedirects) { this(context, listener, userAgent, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, allowCrossProtocolRedirects); @@ -66,7 +67,7 @@ public final class ExtendedDefaultDataSource implements DataSource { * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled when fetching remote data. */ - public ExtendedDefaultDataSource(Context context, TransferListener listener, + public ExtendedDefaultDataSource(Context context, TransferListener listener, String userAgent, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects) { this(context, listener, @@ -83,7 +84,7 @@ public final class ExtendedDefaultDataSource implements DataSource { * @param baseDataSource A {@link DataSource} to use for URI schemes other than file, asset and * content. This {@link DataSource} should normally support at least http(s). */ - public ExtendedDefaultDataSource(Context context, TransferListener listener, + public ExtendedDefaultDataSource(Context context, TransferListener listener, DataSource baseDataSource) { this.baseDataSource = Assertions.checkNotNull(baseDataSource); this.fileDataSource = new FileDataSource(listener); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSourceFactory.java b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSourceFactory.java index daaffd707..ce7f64f87 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSourceFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/secretmedia/ExtendedDefaultDataSourceFactory.java @@ -10,15 +10,15 @@ package org.telegram.messenger.secretmedia; import android.content.Context; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DefaultDataSource; -import org.telegram.messenger.exoplayer2.upstream.DefaultHttpDataSourceFactory; -import org.telegram.messenger.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultDataSource; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; +import com.google.android.exoplayer2.upstream.TransferListener; public final class ExtendedDefaultDataSourceFactory implements DataSource.Factory { private final Context context; - private final TransferListener listener; + private final TransferListener listener; private final DataSource.Factory baseDataSourceFactory; /** @@ -35,7 +35,7 @@ public final class ExtendedDefaultDataSourceFactory implements DataSource.Factor * @param listener An optional listener. */ public ExtendedDefaultDataSourceFactory(Context context, String userAgent, - TransferListener listener) { + TransferListener listener) { this(context, listener, new DefaultHttpDataSourceFactory(userAgent, listener)); } @@ -46,7 +46,7 @@ public final class ExtendedDefaultDataSourceFactory implements DataSource.Factor * for {@link DefaultDataSource}. * @see DefaultDataSource#DefaultDataSource(Context, TransferListener, DataSource) */ - public ExtendedDefaultDataSourceFactory(Context context, TransferListener listener, + public ExtendedDefaultDataSourceFactory(Context context, TransferListener listener, DataSource.Factory baseDataSourceFactory) { this.context = context.getApplicationContext(); this.listener = listener; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java index a1d72a535..159db80c6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java @@ -23,6 +23,7 @@ import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; +import android.os.Build; import android.view.Surface; @TargetApi(17) @@ -118,6 +119,7 @@ public class InputSurface { return mSurface; } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public void setPresentationTime(long nsecs) { EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java index 098d4a006..66db35e51 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java @@ -38,8 +38,6 @@ import com.coremedia.iso.boxes.TrackHeaderBox; import com.googlecode.mp4parser.DataSource; import com.googlecode.mp4parser.util.Matrix; -import org.telegram.messenger.FileLog; - import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -216,7 +214,7 @@ public class MP4Builder { } @Override - public void parse(DataSource dataSource, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + public void parse(DataSource dataSource, ByteBuffer header, long contentSize, BoxParser boxParser) { } @@ -412,7 +410,7 @@ public class MP4Builder { protected void createStsc(Track track, SampleTableBox stbl) { SampleToChunkBox stsc = new SampleToChunkBox(); - stsc.setEntries(new LinkedList()); + stsc.setEntries(new LinkedList<>()); long lastOffset; int lastChunkNumber = 1; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java index 94950ae39..404a71e22 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java @@ -9,8 +9,8 @@ package org.telegram.messenger.video; public class Sample { - private long offset = 0; - private long size = 0; + private long offset; + private long size; public Sample(long offset, long size) { this.offset = offset; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java index b9e6abf97..2ad126c76 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java @@ -28,7 +28,6 @@ import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.SLConfigDescriptor; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; @@ -48,13 +47,13 @@ public class Track { } } - private long trackId = 0; + private long trackId; private ArrayList samples = new ArrayList<>(); private long duration = 0; private int[] sampleCompositions; private String handler; - private AbstractMediaHeaderBox headerBox = null; - private SampleDescriptionBox sampleDescriptionBox = null; + private AbstractMediaHeaderBox headerBox; + private SampleDescriptionBox sampleDescriptionBox; private LinkedList syncSamples = null; private int timeScale; private Date creationTime = new Date(); @@ -63,7 +62,7 @@ public class Track { private float volume = 0; private long[] sampleDurations; private ArrayList samplePresentationTimes = new ArrayList<>(); - private boolean isAudio = false; + private boolean isAudio; private static Map samplingFrequencyIndexMap = new HashMap<>(); private boolean first = true; @@ -267,16 +266,13 @@ public class Track { public void prepare() { ArrayList original = new ArrayList<>(samplePresentationTimes); - Collections.sort(samplePresentationTimes, new Comparator() { - @Override - public int compare(SamplePresentationTime o1, SamplePresentationTime o2) { - if (o1.presentationTime > o2.presentationTime) { - return 1; - } else if (o1.presentationTime < o2.presentationTime) { - return -1; - } - return 0; + Collections.sort(samplePresentationTimes, (o1, o2) -> { + if (o1.presentationTime > o2.presentationTime) { + return 1; + } else if (o1.presentationTime < o2.presentationTime) { + return -1; } + return 0; }); long lastPresentationTimeUs = 0; sampleDurations = new long[samplePresentationTimes.size()]; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java index 7bb4c8d64..188a02424 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java @@ -474,6 +474,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList builder.setColor(0xff2ca5e0); } if (Build.VERSION.SDK_INT >= 26) { + NotificationsController.checkOtherNotificationsChannel(); builder.setChannelId(NotificationsController.OTHER_NOTIFICATIONS_CHANNEL); } if (photo!= null) { @@ -755,8 +756,17 @@ public abstract class VoIPBaseService extends Service implements SensorEventList if(isBluetoothHeadsetConnected() && hasEarpiece()){ switch(audioRouteToSet){ case AUDIO_ROUTE_BLUETOOTH: - am.setBluetoothScoOn(true); - am.setSpeakerphoneOn(false); + if(!bluetoothScoActive){ + needSwitchToBluetoothAfterScoActivates=true; + try { + am.startBluetoothSco(); + } catch (Throwable ignore) { + + } + }else{ + am.setBluetoothScoOn(true); + am.setSpeakerphoneOn(false); + } break; case AUDIO_ROUTE_EARPIECE: am.setBluetoothScoOn(false); @@ -862,7 +872,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList FileLog.d("updateBluetoothHeadsetState: "+connected); isBtHeadsetConnected=connected; final AudioManager am=(AudioManager)getSystemService(AUDIO_SERVICE); - if(connected){ + if(connected && !isRinging() && currentState!=0){ if(bluetoothScoActive){ if(BuildVars.LOGS_ENABLED) FileLog.d("SCO already active, setting audio routing"); @@ -1355,6 +1365,10 @@ public abstract class VoIPBaseService extends Service implements SensorEventList return currentState==STATE_ENDED || currentState==STATE_FAILED; } + protected boolean isRinging(){ + return false; + } + @TargetApi(Build.VERSION_CODES.O) protected PhoneAccountHandle addAccountToTelecomManager(){ TelecomManager tm=(TelecomManager) getSystemService(TELECOM_SERVICE); @@ -1381,6 +1395,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList || "marlin".equals(Build.PRODUCT) // Pixel XL || "walleye".equals(Build.PRODUCT) // Pixel 2 || "taimen".equals(Build.PRODUCT) // Pixel 2 XL + || MessagesController.getGlobalMainSettings().getBoolean("dbg_force_connection_service", false) ; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPController.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPController.java index a4f131cca..4c15be101 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPController.java @@ -25,26 +25,26 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Locale; -public class VoIPController { +public class VoIPController{ - public static final int NET_TYPE_UNKNOWN = 0; - public static final int NET_TYPE_GPRS = 1; - public static final int NET_TYPE_EDGE = 2; - public static final int NET_TYPE_3G = 3; - public static final int NET_TYPE_HSPA = 4; - public static final int NET_TYPE_LTE = 5; - public static final int NET_TYPE_WIFI = 6; - public static final int NET_TYPE_ETHERNET = 7; - public static final int NET_TYPE_OTHER_HIGH_SPEED = 8; - public static final int NET_TYPE_OTHER_LOW_SPEED = 9; - public static final int NET_TYPE_DIALUP = 10; - public static final int NET_TYPE_OTHER_MOBILE = 11; + public static final int NET_TYPE_UNKNOWN=0; + public static final int NET_TYPE_GPRS=1; + public static final int NET_TYPE_EDGE=2; + public static final int NET_TYPE_3G=3; + public static final int NET_TYPE_HSPA=4; + public static final int NET_TYPE_LTE=5; + public static final int NET_TYPE_WIFI=6; + public static final int NET_TYPE_ETHERNET=7; + public static final int NET_TYPE_OTHER_HIGH_SPEED=8; + public static final int NET_TYPE_OTHER_LOW_SPEED=9; + public static final int NET_TYPE_DIALUP=10; + public static final int NET_TYPE_OTHER_MOBILE=11; - public static final int STATE_WAIT_INIT = 1; - public static final int STATE_WAIT_INIT_ACK = 2; - public static final int STATE_ESTABLISHED = 3; - public static final int STATE_FAILED = 4; - public static final int STATE_RECONNECTING = 5; + public static final int STATE_WAIT_INIT=1; + public static final int STATE_WAIT_INIT_ACK=2; + public static final int STATE_ESTABLISHED=3; + public static final int STATE_FAILED=4; + public static final int STATE_RECONNECTING=5; public static final int DATA_SAVING_NEVER=0; public static final int DATA_SAVING_MOBILE=1; @@ -62,79 +62,79 @@ public class VoIPController { public static final int PEER_CAP_GROUP_CALLS=1; - protected long nativeInst = 0; + protected long nativeInst=0; protected long callStartTime; protected ConnectionStateListener listener; - public VoIPController() { - nativeInst = nativeInit(); + public VoIPController(){ + nativeInst=nativeInit(); } - public void start() { + public void start(){ ensureNativeInstance(); nativeStart(nativeInst); } - public void connect() { + public void connect(){ ensureNativeInstance(); nativeConnect(nativeInst); } - public void setRemoteEndpoints(TLRPC.TL_phoneConnection[] endpoints, boolean allowP2p, boolean tcp, int connectionMaxLayer) { - if (endpoints.length == 0) { + public void setRemoteEndpoints(TLRPC.TL_phoneConnection[] endpoints, boolean allowP2p, boolean tcp, int connectionMaxLayer){ + if(endpoints.length==0){ throw new IllegalArgumentException("endpoints size is 0"); } - for (int a = 0; a < endpoints.length; a++) { - TLRPC.TL_phoneConnection endpoint = endpoints[a]; - if (endpoint.ip == null || endpoint.ip.length() == 0) { - throw new IllegalArgumentException("endpoint " + endpoint + " has empty/null ipv4"); + for(int a=0; a=Build.VERSION_CODES.JELLY_BEAN){ + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){ try{ sysAecAvailable=AcousticEchoCanceler.isAvailable(); sysNsAvailable=AcousticEchoCanceler.isAvailable(); @@ -188,12 +188,12 @@ public class VoIPController { } } - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean dump = preferences.getBoolean("dbg_dump_call_stats", false); + SharedPreferences preferences=MessagesController.getGlobalMainSettings(); + boolean dump=preferences.getBoolean("dbg_dump_call_stats", false); nativeSetConfig(nativeInst, recvTimeout, initTimeout, dataSavingOption, !(sysAecAvailable && VoIPServerConfig.getBoolean("use_system_aec", true)), !(sysNsAvailable && VoIPServerConfig.getBoolean("use_system_ns", true)), - true, BuildConfig.DEBUG ? getLogFilePath("voip") : getLogFilePath(callID), BuildConfig.DEBUG && dump ? getLogFilePath("voipStats") : null); + true, BuildConfig.DEBUG ? getLogFilePath("voip"+callID) : getLogFilePath(callID), BuildConfig.DEBUG && dump ? getLogFilePath("voipStats") : null); } public void debugCtl(int request, int param){ @@ -314,7 +314,7 @@ public class VoIPController { private native void nativeSendGroupCallKey(long inst, byte[] key); private native void nativeRequestCallUpgrade(long inst); - public interface ConnectionStateListener { + public interface ConnectionStateListener{ void onConnectionStateChanged(int newState); void onSignalBarCountChanged(int newCount); void onGroupCallKeyReceived(byte[] key); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java index a092cba9d..92205a6af 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -180,6 +180,7 @@ public class VoIPService extends VoIPBaseService{ public void onCreate(){ super.onCreate(); if(callIShouldHavePutIntoIntent!=null && Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ + NotificationsController.checkOtherNotificationsChannel(); Notification.Builder bldr=new Notification.Builder(this, NotificationsController.OTHER_NOTIFICATIONS_CHANNEL) .setSmallIcon(R.drawable.notification) .setContentTitle(LocaleController.getString("VoipOutgoingCall", R.string.VoipOutgoingCall)) @@ -457,6 +458,11 @@ public class VoIPService extends VoIPBaseService{ } } + @Override + protected boolean isRinging(){ + return currentState==STATE_WAITING_INCOMING; + } + public void acceptIncomingCall() { stopRinging(); showNotification(); @@ -755,7 +761,7 @@ public class VoIPService extends VoIPBaseService{ byte[] correctedAuth = new byte[256]; System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; + correctedAuth[a] = 0; } authKey = correctedAuth; } @@ -844,7 +850,7 @@ public class VoIPService extends VoIPBaseService{ byte[] correctedAuth = new byte[256]; System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); for (int a = 0; a < 256 - authKey.length; a++) { - authKey[a] = 0; + correctedAuth[a] = 0; } authKey = correctedAuth; } @@ -944,7 +950,7 @@ public class VoIPService extends VoIPBaseService{ } controller.setRemoteEndpoints(endpoints, call.protocol.udp_p2p && allowP2p, BuildVars.DEBUG_VERSION && prefs.getBoolean("dbg_force_tcp_in_calls", false), call.protocol.max_layer); - if(BuildVars.DEBUG_VERSION && prefs.getBoolean("dbg_force_tcp_in_calls", false)){ + if(prefs.getBoolean("dbg_force_tcp_in_calls", false)){ AndroidUtilities.runOnUIThread(new Runnable(){ @Override public void run(){ @@ -1073,7 +1079,7 @@ public class VoIPService extends VoIPBaseService{ } /*package*/ void onMediaButtonEvent(KeyEvent ev) { - if (ev.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK) { + if (ev.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK || ev.getKeyCode()==KeyEvent.KEYCODE_MEDIA_PAUSE || ev.getKeyCode()==KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { if (ev.getAction() == KeyEvent.ACTION_UP) { if (currentState == STATE_WAITING_INCOMING) { acceptIncomingCall(); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index dba76f413..41ed89afd 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -61,7 +61,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_EDITED = 0x00008000; public static final int MESSAGE_FLAG_MEGAGROUP = 0x80000000; - public static final int LAYER = 82; + public static final int LAYER = 85; public static abstract class DraftMessage extends TLObject { @@ -618,12 +618,11 @@ public class TLRPC { } public static class TL_account_passwordSettings extends TLObject { - public static int constructor = 0x7bd9c3f1; + public static int constructor = 0x9a5c33e5; + public int flags; public String email; - public byte[] secure_salt; - public byte[] secure_secret; - public long secure_secret_id; + public TL_secureSecretSettings secure_settings; public static TL_account_passwordSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_account_passwordSettings.constructor != constructor) { @@ -639,18 +638,24 @@ public class TLRPC { } public void readParams(AbstractSerializedData stream, boolean exception) { - email = stream.readString(exception); - secure_salt = stream.readByteArray(exception); - secure_secret = stream.readByteArray(exception); - secure_secret_id = stream.readInt64(exception); + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + email = stream.readString(exception); + } + if ((flags & 2) != 0) { + secure_settings = TL_secureSecretSettings.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeString(email); - stream.writeByteArray(secure_salt); - stream.writeByteArray(secure_secret); - stream.writeInt64(secure_secret_id); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeString(email); + } + if ((flags & 2) != 0) { + secure_settings.serializeToStream(stream); + } } } @@ -5184,7 +5189,7 @@ public class TLRPC { } public static class TL_inputSecureValue extends TLObject { - public static int constructor = 0x67872e8; + public static int constructor = 0xdb21d0a7; public int flags; public SecureValueType type; @@ -5192,6 +5197,7 @@ public class TLRPC { public InputSecureFile front_side; public InputSecureFile reverse_side; public InputSecureFile selfie; + public ArrayList translation = new ArrayList<>(); public ArrayList files = new ArrayList<>(); public SecurePlainData plain_data; @@ -5223,6 +5229,23 @@ public class TLRPC { if ((flags & 8) != 0) { selfie = InputSecureFile.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 64) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + InputSecureFile object = InputSecureFile.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + translation.add(object); + } + } if ((flags & 16) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -5261,6 +5284,14 @@ public class TLRPC { if ((flags & 8) != 0) { selfie.serializeToStream(stream); } + if ((flags & 64) != 0) { + stream.writeInt32(0x1cb5c415); + int count = translation.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + translation.get(a).serializeToStream(stream); + } + } if ((flags & 16) != 0) { stream.writeInt32(0x1cb5c415); int count = files.size(); @@ -5680,6 +5711,70 @@ public class TLRPC { } } + public static abstract class SecurePasswordKdfAlgo extends TLObject { + + public static SecurePasswordKdfAlgo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + SecurePasswordKdfAlgo result = null; + switch (constructor) { + case 0xbbf2dda0: + result = new TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(); + break; + case 0x86471d92: + result = new TL_securePasswordKdfAlgoSHA512(); + break; + case 0x4a8537: + result = new TL_securePasswordKdfAlgoUnknown(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in SecurePasswordKdfAlgo", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 extends SecurePasswordKdfAlgo { + public static int constructor = 0xbbf2dda0; + + public byte[] salt; + + public void readParams(AbstractSerializedData stream, boolean exception) { + salt = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(salt); + } + } + + public static class TL_securePasswordKdfAlgoSHA512 extends SecurePasswordKdfAlgo { + public static int constructor = 0x86471d92; + + public byte[] salt; + + public void readParams(AbstractSerializedData stream, boolean exception) { + salt = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(salt); + } + } + + public static class TL_securePasswordKdfAlgoUnknown extends SecurePasswordKdfAlgo { + public static int constructor = 0x4a8537; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static abstract class BotInfo extends TLObject { public int user_id; public String description; @@ -6085,6 +6180,89 @@ public class TLRPC { } } + public static abstract class SecureRequiredType extends TLObject { + + public static SecureRequiredType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + SecureRequiredType result = null; + switch (constructor) { + case 0x829d99da: + result = new TL_secureRequiredType(); + break; + case 0x27477b4: + result = new TL_secureRequiredTypeOneOf(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in SecureRequiredType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_secureRequiredType extends SecureRequiredType { + public static int constructor = 0x829d99da; + + public int flags; + public boolean native_names; + public boolean selfie_required; + public boolean translation_required; + public SecureValueType type; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + native_names = (flags & 1) != 0; + selfie_required = (flags & 2) != 0; + translation_required = (flags & 4) != 0; + type = SecureValueType.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = native_names ? (flags | 1) : (flags &~ 1); + flags = selfie_required ? (flags | 2) : (flags &~ 2); + flags = translation_required ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + type.serializeToStream(stream); + } + } + + public static class TL_secureRequiredTypeOneOf extends SecureRequiredType { + public static int constructor = 0x27477b4; + + public ArrayList types = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + SecureRequiredType object = SecureRequiredType.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + types.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = types.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + types.get(a).serializeToStream(stream); + } + } + } + public static abstract class InputPrivacyKey extends TLObject { public static InputPrivacyKey TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -8757,24 +8935,33 @@ public class TLRPC { public static SecureValueError TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { SecureValueError result = null; switch (constructor) { + case 0x7a700873: + result = new TL_secureValueErrorFile(); + break; case 0xbe3dfa: result = new TL_secureValueErrorFrontSide(); break; - case 0x868a2aa5: - result = new TL_secureValueErrorReverseSide(); - break; case 0x666220e9: result = new TL_secureValueErrorFiles(); break; - case 0xe537ced6: - result = new TL_secureValueErrorSelfie(); + case 0x868a2aa5: + result = new TL_secureValueErrorReverseSide(); break; - case 0x7a700873: - result = new TL_secureValueErrorFile(); + case 0xa1144770: + result = new TL_secureValueErrorTranslationFile(); + break; + case 0x869d758f: + result = new TL_secureValueError(); break; case 0xe8a40bd9: result = new TL_secureValueErrorData(); break; + case 0x34636dd8: + result = new TL_secureValueErrorTranslationFiles(); + break; + case 0xe537ced6: + result = new TL_secureValueErrorSelfie(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in SecureValueError", constructor)); @@ -8786,8 +8973,8 @@ public class TLRPC { } } - public static class TL_secureValueErrorFrontSide extends SecureValueError { - public static int constructor = 0xbe3dfa; + public static class TL_secureValueErrorFile extends SecureValueError { + public static int constructor = 0x7a700873; public SecureValueType type; public byte[] file_hash; @@ -8807,8 +8994,8 @@ public class TLRPC { } } - public static class TL_secureValueErrorReverseSide extends SecureValueError { - public static int constructor = 0x868a2aa5; + public static class TL_secureValueErrorFrontSide extends SecureValueError { + public static int constructor = 0xbe3dfa; public SecureValueType type; public byte[] file_hash; @@ -8864,8 +9051,8 @@ public class TLRPC { } } - public static class TL_secureValueErrorSelfie extends SecureValueError { - public static int constructor = 0xe537ced6; + public static class TL_secureValueErrorReverseSide extends SecureValueError { + public static int constructor = 0x868a2aa5; public SecureValueType type; public byte[] file_hash; @@ -8885,8 +9072,8 @@ public class TLRPC { } } - public static class TL_secureValueErrorFile extends SecureValueError { - public static int constructor = 0x7a700873; + public static class TL_secureValueErrorTranslationFile extends SecureValueError { + public static int constructor = 0xa1144770; public SecureValueType type; public byte[] file_hash; @@ -8906,6 +9093,27 @@ public class TLRPC { } } + public static class TL_secureValueError extends SecureValueError { + public static int constructor = 0x869d758f; + + public SecureValueType type; + public byte[] hash; + public String text; + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = SecureValueType.TLdeserialize(stream, stream.readInt32(exception), exception); + hash = stream.readByteArray(exception); + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + type.serializeToStream(stream); + stream.writeByteArray(hash); + stream.writeString(text); + } + } + public static class TL_secureValueErrorData extends SecureValueError { public static int constructor = 0xe8a40bd9; @@ -8930,8 +9138,65 @@ public class TLRPC { } } + public static class TL_secureValueErrorTranslationFiles extends SecureValueError { + public static int constructor = 0x34636dd8; + + public SecureValueType type; + public ArrayList file_hash = new ArrayList<>(); + public String text; + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = SecureValueType.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + file_hash.add(stream.readByteArray(exception)); + } + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + type.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = file_hash.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeByteArray(file_hash.get(a)); + } + stream.writeString(text); + } + } + + public static class TL_secureValueErrorSelfie extends SecureValueError { + public static int constructor = 0xe537ced6; + + public SecureValueType type; + public byte[] file_hash; + public String text; + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = SecureValueType.TLdeserialize(stream, stream.readInt32(exception), exception); + file_hash = stream.readByteArray(exception); + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + type.serializeToStream(stream); + stream.writeByteArray(file_hash); + stream.writeString(text); + } + } + public static class TL_secureValue extends TLObject { - public static int constructor = 0xb4b4b699; + public static int constructor = 0x187fa0ca; public int flags; public SecureValueType type; @@ -8939,6 +9204,7 @@ public class TLRPC { public SecureFile front_side; public SecureFile reverse_side; public SecureFile selfie; + public ArrayList translation = new ArrayList<>(); public ArrayList files = new ArrayList<>(); public SecurePlainData plain_data; public byte[] hash; @@ -8971,6 +9237,23 @@ public class TLRPC { if ((flags & 8) != 0) { selfie = SecureFile.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 64) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + SecureFile object = SecureFile.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + translation.add(object); + } + } if ((flags & 16) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -9010,6 +9293,14 @@ public class TLRPC { if ((flags & 8) != 0) { selfie.serializeToStream(stream); } + if ((flags & 64) != 0) { + stream.writeInt32(0x1cb5c415); + int count = translation.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + translation.get(a).serializeToStream(stream); + } + } if ((flags & 16) != 0) { stream.writeInt32(0x1cb5c415); int count = files.size(); @@ -12977,6 +13268,61 @@ public class TLRPC { } } + public static abstract class PasswordKdfAlgo extends TLObject { + + public static PasswordKdfAlgo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PasswordKdfAlgo result = null; + switch (constructor) { + case 0xd45ab096: + result = new TL_passwordKdfAlgoUnknown(); + break; + case 0x3a912d4a: + result = new TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PasswordKdfAlgo", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_passwordKdfAlgoUnknown extends PasswordKdfAlgo { + public static int constructor = 0xd45ab096; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow extends PasswordKdfAlgo { + public static int constructor = 0x3a912d4a; + + public byte[] salt1; + public byte[] salt2; + public int g; + public byte[] p; + + public void readParams(AbstractSerializedData stream, boolean exception) { + salt1 = stream.readByteArray(exception); + salt2 = stream.readByteArray(exception); + g = stream.readInt32(exception); + p = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(salt1); + stream.writeByteArray(salt2); + stream.writeInt32(g); + stream.writeByteArray(p); + } + } + public static abstract class ContactLink extends TLObject { public static ContactLink TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -16870,86 +17216,138 @@ public class TLRPC { } } - public static abstract class account_Password extends TLObject { - public int flags; - public boolean has_recovery; - public boolean has_secure_values; - public byte[] current_salt; - public byte[] new_salt; - public byte[] new_secure_salt; - public byte[] secure_random; - public String hint; - public String email_unconfirmed_pattern; + public static abstract class InputCheckPasswordSRP extends TLObject { - public static account_Password TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - account_Password result = null; - switch (constructor) { - case 0xca39b447: - result = new TL_account_password(); - break; - case 0x5ea182f6: - result = new TL_account_noPassword(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in account_Password", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } + public static InputCheckPasswordSRP TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputCheckPasswordSRP result = null; + switch (constructor) { + case 0x9880f658: + result = new TL_inputCheckPasswordEmpty(); + break; + case 0xd27ff082: + result = new TL_inputCheckPasswordSRP(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputCheckPasswordSRP", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } - public static class TL_account_password extends account_Password { - public static int constructor = 0xca39b447; + public static class TL_inputCheckPasswordEmpty extends InputCheckPasswordSRP { + public static int constructor = 0x9880f658; - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - has_recovery = (flags & 1) != 0; - has_secure_values = (flags & 2) != 0; - current_salt = stream.readByteArray(exception); - new_salt = stream.readByteArray(exception); - new_secure_salt = stream.readByteArray(exception); - secure_random = stream.readByteArray(exception); - hint = stream.readString(exception); - email_unconfirmed_pattern = stream.readString(exception); - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = has_recovery ? (flags | 1) : (flags &~ 1); - flags = has_secure_values ? (flags | 2) : (flags &~ 2); - stream.writeInt32(flags); - stream.writeByteArray(current_salt); - stream.writeByteArray(new_salt); - stream.writeByteArray(new_secure_salt); - stream.writeByteArray(secure_random); - stream.writeString(hint); - stream.writeString(email_unconfirmed_pattern); - } - } + public static class TL_inputCheckPasswordSRP extends InputCheckPasswordSRP { + public static int constructor = 0xd27ff082; - public static class TL_account_noPassword extends account_Password { - public static int constructor = 0x5ea182f6; + public long srp_id; + public byte[] A; + public byte[] M1; + public void readParams(AbstractSerializedData stream, boolean exception) { + srp_id = stream.readInt64(exception); + A = stream.readByteArray(exception); + M1 = stream.readByteArray(exception); + } - public void readParams(AbstractSerializedData stream, boolean exception) { - new_salt = stream.readByteArray(exception); - new_secure_salt = stream.readByteArray(exception); - secure_random = stream.readByteArray(exception); - email_unconfirmed_pattern = stream.readString(exception); - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(srp_id); + stream.writeByteArray(A); + stream.writeByteArray(M1); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(new_salt); - stream.writeByteArray(new_secure_salt); - stream.writeByteArray(secure_random); - stream.writeString(email_unconfirmed_pattern); - } - } + public static class TL_account_password extends TLObject { + public static int constructor = 0xad2641f8; + + public int flags; + public boolean has_recovery; + public boolean has_secure_values; + public boolean has_password; + public PasswordKdfAlgo current_algo; + public byte[] srp_B; + public long srp_id; + public String hint; + public String email_unconfirmed_pattern; + public PasswordKdfAlgo new_algo; + public SecurePasswordKdfAlgo new_secure_algo; + public byte[] secure_random; + + public static TL_account_password TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_account_password.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_password", constructor)); + } else { + return null; + } + } + TL_account_password result = new TL_account_password(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + has_recovery = (flags & 1) != 0; + has_secure_values = (flags & 2) != 0; + has_password = (flags & 4) != 0; + if ((flags & 4) != 0) { + current_algo = PasswordKdfAlgo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + srp_B = stream.readByteArray(exception); + } + if ((flags & 4) != 0) { + srp_id = stream.readInt64(exception); + } + if ((flags & 8) != 0) { + hint = stream.readString(exception); + } + if ((flags & 16) != 0) { + email_unconfirmed_pattern = stream.readString(exception); + } + new_algo = PasswordKdfAlgo.TLdeserialize(stream, stream.readInt32(exception), exception); + new_secure_algo = SecurePasswordKdfAlgo.TLdeserialize(stream, stream.readInt32(exception), exception); + secure_random = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = has_recovery ? (flags | 1) : (flags &~ 1); + flags = has_secure_values ? (flags | 2) : (flags &~ 2); + flags = has_password ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 4) != 0) { + current_algo.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeByteArray(srp_B); + } + if ((flags & 4) != 0) { + stream.writeInt64(srp_id); + } + if ((flags & 8) != 0) { + stream.writeString(hint); + } + if ((flags & 16) != 0) { + stream.writeString(email_unconfirmed_pattern); + } + new_algo.serializeToStream(stream); + new_secure_algo.serializeToStream(stream); + stream.writeByteArray(secure_random); + } + } public static abstract class UserProfilePhoto extends TLObject { public long photo_id; @@ -18744,6 +19142,40 @@ public class TLRPC { } } + public static class TL_secureSecretSettings extends TLObject { + public static int constructor = 0x1527bcac; + + public SecurePasswordKdfAlgo secure_algo; + public byte[] secure_secret; + public long secure_secret_id; + + public static TL_secureSecretSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_secureSecretSettings.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_secureSecretSettings", constructor)); + } else { + return null; + } + } + TL_secureSecretSettings result = new TL_secureSecretSettings(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + secure_algo = SecurePasswordKdfAlgo.TLdeserialize(stream, stream.readInt32(exception), exception); + secure_secret = stream.readByteArray(exception); + secure_secret_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + secure_algo.serializeToStream(stream); + stream.writeByteArray(secure_secret); + stream.writeInt64(secure_secret_id); + } + } + public static class TL_messages_foundGifs extends TLObject { public static int constructor = 0x450a1c0a; @@ -19088,11 +19520,10 @@ public class TLRPC { } public static class TL_account_authorizationForm extends TLObject { - public static int constructor = 0xcb976d53; + public static int constructor = 0xad2e1cd8; public int flags; - public boolean selfie_required; - public ArrayList required_types = new ArrayList<>(); + public ArrayList required_types = new ArrayList<>(); public ArrayList values = new ArrayList<>(); public ArrayList errors = new ArrayList<>(); public ArrayList users = new ArrayList<>(); @@ -19113,7 +19544,6 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); - selfie_required = (flags & 2) != 0; int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -19123,7 +19553,7 @@ public class TLRPC { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - SecureValueType object = SecureValueType.TLdeserialize(stream, stream.readInt32(exception), exception); + SecureRequiredType object = SecureRequiredType.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } @@ -19181,7 +19611,6 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = selfie_required ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); stream.writeInt32(0x1cb5c415); int count = required_types.size(); @@ -24578,17 +25007,64 @@ public class TLRPC { } } + public static abstract class help_PassportConfig extends TLObject { + + public static help_PassportConfig TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_PassportConfig result = null; + switch (constructor) { + case 0xbfb9f457: + result = new TL_help_passportConfigNotModified(); + break; + case 0xa098d6af: + result = new TL_help_passportConfig(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_PassportConfig", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_passportConfigNotModified extends help_PassportConfig { + public static int constructor = 0xbfb9f457; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_passportConfig extends help_PassportConfig { + public static int constructor = 0xa098d6af; + + public int hash; + public TL_dataJSON countries_langs; + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + countries_langs = TL_dataJSON.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + countries_langs.serializeToStream(stream); + } + } + public static class TL_account_passwordInputSettings extends TLObject { - public static int constructor = 0x21ffa60d; + public static int constructor = 0xc23727c9; public int flags; - public byte[] new_salt; + public PasswordKdfAlgo new_algo; public byte[] new_password_hash; public String hint; public String email; - public byte[] new_secure_salt; - public byte[] new_secure_secret; - public long new_secure_secret_id; + public TL_secureSecretSettings new_secure_settings; public static TL_account_passwordInputSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_account_passwordInputSettings.constructor != constructor) { @@ -24606,7 +25082,7 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); if ((flags & 1) != 0) { - new_salt = stream.readByteArray(exception); + new_algo = PasswordKdfAlgo.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 1) != 0) { new_password_hash = stream.readByteArray(exception); @@ -24618,13 +25094,7 @@ public class TLRPC { email = stream.readString(exception); } if ((flags & 4) != 0) { - new_secure_salt = stream.readByteArray(exception); - } - if ((flags & 4) != 0) { - new_secure_secret = stream.readByteArray(exception); - } - if ((flags & 4) != 0) { - new_secure_secret_id = stream.readInt64(exception); + new_secure_settings = TL_secureSecretSettings.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -24632,7 +25102,7 @@ public class TLRPC { stream.writeInt32(constructor); stream.writeInt32(flags); if ((flags & 1) != 0) { - stream.writeByteArray(new_salt); + new_algo.serializeToStream(stream); } if ((flags & 1) != 0) { stream.writeByteArray(new_password_hash); @@ -24644,13 +25114,7 @@ public class TLRPC { stream.writeString(email); } if ((flags & 4) != 0) { - stream.writeByteArray(new_secure_salt); - } - if ((flags & 4) != 0) { - stream.writeByteArray(new_secure_secret); - } - if ((flags & 4) != 0) { - stream.writeInt64(new_secure_secret_id); + new_secure_settings.serializeToStream(stream); } } } @@ -26104,6 +26568,21 @@ public class TLRPC { } } + public static class TL_help_getPassportConfig extends TLObject { + public static int constructor = 0xc661ad08; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_PassportConfig.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + public static class TL_messages_readHistory extends TLObject { public static int constructor = 0xe306d3a; @@ -27683,7 +28162,7 @@ public class TLRPC { public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return account_Password.TLdeserialize(stream, constructor, exception); + return TL_account_password.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -27691,109 +28170,109 @@ public class TLRPC { } } - public static class TL_account_getPasswordSettings extends TLObject { - public static int constructor = 0xbc8d11bb; + public static class TL_account_getPasswordSettings extends TLObject { + public static int constructor = 0x9cd4eaf9; - public byte[] current_password_hash; + public InputCheckPasswordSRP password; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_account_passwordSettings.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(current_password_hash); - } - } - - public static class TL_account_updatePasswordSettings extends TLObject { - public static int constructor = 0xfa7c4b86; - - public byte[] current_password_hash; - public TL_account_passwordInputSettings new_settings; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return Bool.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(current_password_hash); - new_settings.serializeToStream(stream); - } - } - - public static class TL_account_sendConfirmPhoneCode extends TLObject { - public static int constructor = 0x1516d7bd; - - public int flags; - public boolean allow_flashcall; - public String hash; - public boolean current_number; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_sentCode.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = allow_flashcall ? (flags | 1) : (flags &~ 1); - stream.writeInt32(flags); - stream.writeString(hash); - if ((flags & 1) != 0) { - stream.writeBool(current_number); - } - } - } - - public static class TL_account_confirmPhone extends TLObject { - public static int constructor = 0x5f2178c3; - - public String phone_code_hash; - public String phone_code; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return Bool.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(phone_code_hash); - stream.writeString(phone_code); - } - } - - public static class TL_account_getTmpPassword extends TLObject { - public static int constructor = 0x4a82327e; - - public byte[] password_hash; - public int period; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_account_tmpPassword.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(password_hash); - stream.writeInt32(period); - } - } - - public static class TL_auth_checkPassword extends TLObject { - public static int constructor = 0xa63011e; - - public byte[] password_hash; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_auth_authorization.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_passwordSettings.TLdeserialize(stream, constructor, exception); + } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(password_hash); - } - } + stream.writeInt32(constructor); + password.serializeToStream(stream); + } + } + + public static class TL_account_updatePasswordSettings extends TLObject { + public static int constructor = 0xa59b102f; + + public InputCheckPasswordSRP password; + public TL_account_passwordInputSettings new_settings; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + password.serializeToStream(stream); + new_settings.serializeToStream(stream); + } + } + + public static class TL_account_sendConfirmPhoneCode extends TLObject { + public static int constructor = 0x1516d7bd; + + public int flags; + public boolean allow_flashcall; + public String hash; + public boolean current_number; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_sentCode.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = allow_flashcall ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(hash); + if ((flags & 1) != 0) { + stream.writeBool(current_number); + } + } + } + + public static class TL_account_confirmPhone extends TLObject { + public static int constructor = 0x5f2178c3; + + public String phone_code_hash; + public String phone_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_code_hash); + stream.writeString(phone_code); + } + } + + public static class TL_account_getTmpPassword extends TLObject { + public static int constructor = 0x449e0b51; + + public InputCheckPasswordSRP password; + public int period; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_tmpPassword.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + password.serializeToStream(stream); + stream.writeInt32(period); + } + } + + public static class TL_auth_checkPassword extends TLObject { + public static int constructor = 0xd18b4d16; + + public InputCheckPasswordSRP password; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + password.serializeToStream(stream); + } + } public static class TL_auth_requestPasswordRecovery extends TLObject { public static int constructor = 0xd897bc66; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index b75ce9f63..3a4737e30 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -91,12 +91,9 @@ public class ActionBar extends FrameLayout { public ActionBar(Context context) { super(context); - setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (titleActionRunnable != null) { - titleActionRunnable.run(); - } + setOnClickListener(v -> { + if (titleActionRunnable != null) { + titleActionRunnable.run(); } }); } @@ -114,16 +111,13 @@ public class ActionBar extends FrameLayout { backButtonImageView.setPadding(AndroidUtilities.dp(1), 0, 0, 0); addView(backButtonImageView, LayoutHelper.createFrame(54, 54, Gravity.LEFT | Gravity.TOP)); - backButtonImageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (!actionModeVisible && isSearchFieldVisible) { - closeSearchField(); - return; - } - if (actionBarMenuOnItemClick != null) { - actionBarMenuOnItemClick.onItemClick(-1); - } + backButtonImageView.setOnClickListener(v -> { + if (!actionModeVisible && isSearchFieldVisible) { + closeSearchField(); + return; + } + if (actionBarMenuOnItemClick != null) { + actionBarMenuOnItemClick.onItemClick(-1); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 81dcf197c..14aa19f39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -97,6 +97,9 @@ public class ActionBarLayout extends FrameLayout { @Override public boolean hasOverlappingRendering() { + if (Build.VERSION.SDK_INT >= 28) { + return true; + } return false; } @@ -819,12 +822,9 @@ public class ActionBarLayout extends FrameLayout { transitionAnimationStartTime = System.currentTimeMillis(); transitionAnimationInProgress = true; - onOpenAnimationEndRunnable = new Runnable() { - @Override - public void run() { - fragment.onTransitionAnimationEnd(true, false); - fragment.onBecomeFullyVisible(); - } + onOpenAnimationEndRunnable = () -> { + fragment.onTransitionAnimationEnd(true, false); + fragment.onBecomeFullyVisible(); }; ArrayList animators = new ArrayList<>(); animators.add(ObjectAnimator.ofFloat(this, "alpha", 0.0f, 1.0f)); @@ -849,31 +849,23 @@ public class ActionBarLayout extends FrameLayout { transitionAnimationPreviewMode = preview; transitionAnimationStartTime = System.currentTimeMillis(); transitionAnimationInProgress = true; - onOpenAnimationEndRunnable = new Runnable() { - @Override - public void run() { - if (preview) { - inPreviewMode = true; - transitionAnimationPreviewMode = false; - containerView.setScaleX(1.0f); - containerView.setScaleY(1.0f); - } else { - presentFragmentInternalRemoveOld(removeLast, currentFragment); - containerView.setTranslationX(0); - } - fragment.onTransitionAnimationEnd(true, false); - fragment.onBecomeFullyVisible(); + onOpenAnimationEndRunnable = () -> { + if (preview) { + inPreviewMode = true; + transitionAnimationPreviewMode = false; + containerView.setScaleX(1.0f); + containerView.setScaleY(1.0f); + } else { + presentFragmentInternalRemoveOld(removeLast, currentFragment); + containerView.setTranslationX(0); } + fragment.onTransitionAnimationEnd(true, false); + fragment.onBecomeFullyVisible(); }; fragment.onTransitionAnimationStart(true, false); AnimatorSet animation = null; if (!preview) { - animation = fragment.onCustomTransitionAnimation(true, new Runnable() { - @Override - public void run() { - onAnimationEndCheck(false); - } - }); + animation = fragment.onCustomTransitionAnimation(true, () -> onAnimationEndCheck(false)); } if (animation == null) { containerView.setAlpha(0.0f); @@ -1089,31 +1081,23 @@ public class ActionBarLayout extends FrameLayout { transitionAnimationStartTime = System.currentTimeMillis(); transitionAnimationInProgress = true; final BaseFragment previousFragmentFinal = previousFragment; - onCloseAnimationEndRunnable = new Runnable() { - @Override - public void run() { - if (inPreviewMode || transitionAnimationPreviewMode) { - containerViewBack.setScaleX(1.0f); - containerViewBack.setScaleY(1.0f); - inPreviewMode = false; - transitionAnimationPreviewMode = false; - } else { - containerViewBack.setTranslationX(0); - } - closeLastFragmentInternalRemoveOld(currentFragment); - currentFragment.onTransitionAnimationEnd(false, false); - previousFragmentFinal.onTransitionAnimationEnd(true, true); - previousFragmentFinal.onBecomeFullyVisible(); + onCloseAnimationEndRunnable = () -> { + if (inPreviewMode || transitionAnimationPreviewMode) { + containerViewBack.setScaleX(1.0f); + containerViewBack.setScaleY(1.0f); + inPreviewMode = false; + transitionAnimationPreviewMode = false; + } else { + containerViewBack.setTranslationX(0); } + closeLastFragmentInternalRemoveOld(currentFragment); + currentFragment.onTransitionAnimationEnd(false, false); + previousFragmentFinal.onTransitionAnimationEnd(true, true); + previousFragmentFinal.onBecomeFullyVisible(); }; AnimatorSet animation = null; if (!inPreviewMode && !transitionAnimationPreviewMode) { - animation = currentFragment.onCustomTransitionAnimation(false, new Runnable() { - @Override - public void run() { - onAnimationEndCheck(false); - } - }); + animation = currentFragment.onCustomTransitionAnimation(false, () -> onAnimationEndCheck(false)); } if (animation == null) { if (containerView.isKeyboardVisible || containerViewBack.isKeyboardVisible) { @@ -1144,17 +1128,14 @@ public class ActionBarLayout extends FrameLayout { transitionAnimationStartTime = System.currentTimeMillis(); transitionAnimationInProgress = true; - onCloseAnimationEndRunnable = new Runnable() { - @Override - public void run() { - removeFragmentFromStackInternal(currentFragment); - setVisibility(GONE); - if (backgroundView != null) { - backgroundView.setVisibility(GONE); - } - if (drawerLayoutContainer != null) { - drawerLayoutContainer.setAllowOpenDrawer(true, false); - } + onCloseAnimationEndRunnable = () -> { + removeFragmentFromStackInternal(currentFragment); + setVisibility(GONE); + if (backgroundView != null) { + backgroundView.setVisibility(GONE); + } + if (drawerLayoutContainer != null) { + drawerLayoutContainer.setAllowOpenDrawer(true, false); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index d7c5d6c74..e86cf096b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -76,19 +76,16 @@ public class ActionBarMenu extends LinearLayout { menuItem.iconView.setImageResource(icon); } addView(menuItem, new LinearLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT)); - menuItem.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - ActionBarMenuItem item = (ActionBarMenuItem) view; - if (item.hasSubMenu()) { - if (parentActionBar.actionBarMenuOnItemClick.canOpenMenu()) { - item.toggleSubMenu(); - } - } else if (item.isSearchField()) { - parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true)); - } else { - onItemClick((Integer) view.getTag()); + menuItem.setOnClickListener(view -> { + ActionBarMenuItem item = (ActionBarMenuItem) view; + if (item.hasSubMenu()) { + if (parentActionBar.actionBarMenuOnItemClick.canOpenMenu()) { + item.toggleSubMenu(); } + } else if (item.isSearchField()) { + parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true)); + } else { + onItemClick((Integer) view.getTag()); } }); return menuItem; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 45e858393..9c53a4d2d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -122,14 +122,11 @@ public class ActionBarMenuItem extends FrameLayout { public boolean onTouchEvent(MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { if (longClickEnabled && hasSubMenu() && (popupWindow == null || popupWindow != null && !popupWindow.isShowing())) { - showMenuRunnable = new Runnable() { - @Override - public void run() { - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - toggleSubMenu(); + showMenuRunnable = () -> { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); } + toggleSubMenu(); }; AndroidUtilities.runOnUIThread(showMenuRunnable, 200); } @@ -221,26 +218,20 @@ public class ActionBarMenuItem extends FrameLayout { rect = new Rect(); location = new int[2]; popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); - popupLayout.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - if (popupWindow != null && popupWindow.isShowing()) { - v.getHitRect(rect); - if (!rect.contains((int) event.getX(), (int) event.getY())) { - popupWindow.dismiss(); - } + popupLayout.setOnTouchListener((v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (popupWindow != null && popupWindow.isShowing()) { + v.getHitRect(rect); + if (!rect.contains((int) event.getX(), (int) event.getY())) { + popupWindow.dismiss(); } } - return false; } + return false; }); - popupLayout.setDispatchKeyEventListener(new ActionBarPopupWindow.OnDispatchKeyEventListener() { - @Override - public void onDispatchKeyEvent(KeyEvent keyEvent) { - if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(); - } + popupLayout.setDispatchKeyEventListener(keyEvent -> { + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); } }); } @@ -255,21 +246,18 @@ public class ActionBarMenuItem extends FrameLayout { view.setLayoutParams(new LinearLayout.LayoutParams(width, height)); popupLayout.addView(view); view.setTag(id); - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (popupWindow != null && popupWindow.isShowing()) { - if (processedPopupClick) { - return; - } - processedPopupClick = true; - popupWindow.dismiss(allowCloseAnimation); - } - if (parentMenu != null) { - parentMenu.onItemClick((Integer) view.getTag()); - } else if (delegate != null) { - delegate.onItemClick((Integer) view.getTag()); + view.setOnClickListener(view1 -> { + if (popupWindow != null && popupWindow.isShowing()) { + if (processedPopupClick) { + return; } + processedPopupClick = true; + popupWindow.dismiss(allowCloseAnimation); + } + if (parentMenu != null) { + parentMenu.onItemClick((Integer) view1.getTag()); + } else if (delegate != null) { + delegate.onItemClick((Integer) view1.getTag()); } }); view.setBackgroundDrawable(Theme.getSelectorDrawable(false)); @@ -299,21 +287,18 @@ public class ActionBarMenuItem extends FrameLayout { layoutParams.height = AndroidUtilities.dp(48); textView.setLayoutParams(layoutParams); - textView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (popupWindow != null && popupWindow.isShowing()) { - if (processedPopupClick) { - return; - } - processedPopupClick = true; - popupWindow.dismiss(allowCloseAnimation); - } - if (parentMenu != null) { - parentMenu.onItemClick((Integer) view.getTag()); - } else if (delegate != null) { - delegate.onItemClick((Integer) view.getTag()); + textView.setOnClickListener(view -> { + if (popupWindow != null && popupWindow.isShowing()) { + if (processedPopupClick) { + return; } + processedPopupClick = true; + popupWindow.dismiss(allowCloseAnimation); + } + if (parentMenu != null) { + parentMenu.onItemClick((Integer) view.getTag()); + } else if (delegate != null) { + delegate.onItemClick((Integer) view.getTag()); } }); return textView; @@ -382,15 +367,12 @@ public class ActionBarMenuItem extends FrameLayout { popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); popupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); popupWindow.getContentView().setFocusableInTouchMode(true); - popupWindow.getContentView().setOnKeyListener(new OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && event.getRepeatCount() == 0 && event.getAction() == KeyEvent.ACTION_UP && popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(); - return true; - } - return false; + popupWindow.getContentView().setOnKeyListener((v, keyCode, event) -> { + if (keyCode == KeyEvent.KEYCODE_MENU && event.getRepeatCount() == 0 && event.getAction() == KeyEvent.ACTION_UP && popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); + return true; } + return false; }); } processedPopupClick = false; @@ -562,17 +544,14 @@ public class ActionBarMenuItem extends FrameLayout { } }); } - searchField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (event != null && (event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH || event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { - AndroidUtilities.hideKeyboard(searchField); - if (listener != null) { - listener.onSearchPressed(searchField); - } + searchField.setOnEditorActionListener((v, actionId, event) -> { + if (event != null && (event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH || event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + AndroidUtilities.hideKeyboard(searchField); + if (listener != null) { + listener.onSearchPressed(searchField); } - return false; } + return false; }); searchField.addTextChangedListener(new TextWatcher() { @Override @@ -614,21 +593,18 @@ public class ActionBarMenuItem extends FrameLayout { clearButton.setImageDrawable(progressDrawable = new CloseProgressDrawable2()); clearButton.setColorFilter(new PorterDuffColorFilter(parentMenu.parentActionBar.itemsColor, PorterDuff.Mode.MULTIPLY)); clearButton.setScaleType(ImageView.ScaleType.CENTER); - clearButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (searchField.length() != 0) { - searchField.setText(""); - } else if (searchFieldCaption != null && searchFieldCaption.getVisibility() == VISIBLE) { - searchFieldCaption.setVisibility(GONE); - //clearButton.setAlpha(searchField.length() == 0 && searchFieldCaption.getVisibility() != VISIBLE ? 0.6f : 1.0f); - if (listener != null) { - listener.onCaptionCleared(); - } + clearButton.setOnClickListener(v -> { + if (searchField.length() != 0) { + searchField.setText(""); + } else if (searchFieldCaption != null && searchFieldCaption.getVisibility() == VISIBLE) { + searchFieldCaption.setVisibility(GONE); + //clearButton.setAlpha(searchField.length() == 0 && searchFieldCaption.getVisibility() != VISIBLE ? 0.6f : 1.0f); + if (listener != null) { + listener.onCaptionCleared(); } - searchField.requestFocus(); - AndroidUtilities.showKeyboard(searchField); } + searchField.requestFocus(); + AndroidUtilities.showKeyboard(searchField); }); searchContainer.addView(clearButton, LayoutHelper.createFrame(48, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index a8e3a9632..a83422981 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -56,11 +56,8 @@ public class ActionBarPopupWindow extends PopupWindow { superListenerField = f; } - private static final ViewTreeObserver.OnScrollChangedListener NOP = new ViewTreeObserver.OnScrollChangedListener() { - @Override - public void onScrollChanged() { - /* do nothing */ - } + private static final ViewTreeObserver.OnScrollChangedListener NOP = () -> { + /* do nothing */ }; private ViewTreeObserver.OnScrollChangedListener mSuperScrollListener; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index bf40e3bbe..0e0490b3f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -97,12 +97,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { private Drawable shadowDrawable; private Rect backgroundPaddings; - private Runnable dismissRunnable = new Runnable() { - @Override - public void run() { - dismiss(); - } - }; + private Runnable dismissRunnable = this::dismiss; public static class AlertDialogCell extends FrameLayout { @@ -269,28 +264,25 @@ public class AlertDialog extends Dialog implements Drawable.Callback { inLayout = false; if (lastScreenWidth != AndroidUtilities.displaySize.x) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - lastScreenWidth = AndroidUtilities.displaySize.x; - final int calculatedWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(56); - int maxWidth; - if (AndroidUtilities.isTablet()) { - if (AndroidUtilities.isSmallTablet()) { - maxWidth = AndroidUtilities.dp(446); - } else { - maxWidth = AndroidUtilities.dp(496); - } + AndroidUtilities.runOnUIThread(() -> { + lastScreenWidth = AndroidUtilities.displaySize.x; + final int calculatedWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(56); + int maxWidth; + if (AndroidUtilities.isTablet()) { + if (AndroidUtilities.isSmallTablet()) { + maxWidth = AndroidUtilities.dp(446); } else { - maxWidth = AndroidUtilities.dp(356); + maxWidth = AndroidUtilities.dp(496); } - - Window window = getWindow(); - WindowManager.LayoutParams params = new WindowManager.LayoutParams(); - params.copyFrom(window.getAttributes()); - params.width = Math.min(maxWidth, calculatedWidth) + backgroundPaddings.left + backgroundPaddings.right; - window.setAttributes(params); + } else { + maxWidth = AndroidUtilities.dp(356); } + + Window window = getWindow(); + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.copyFrom(window.getAttributes()); + params.width = Math.min(maxWidth, calculatedWidth) + backgroundPaddings.left + backgroundPaddings.right; + window.setAttributes(params); }); } } @@ -300,13 +292,10 @@ public class AlertDialog extends Dialog implements Drawable.Callback { super.onLayout(changed, l, t, r, b); if (contentScrollView != null) { if (onScrollChangedListener == null) { - onScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { - @Override - public void onScrollChanged() { - runShadowAnimation(0, titleTextView != null && contentScrollView.getScrollY() > scrollContainer.getTop()); - runShadowAnimation(1, buttonsLayout != null && contentScrollView.getScrollY() + contentScrollView.getHeight() < scrollContainer.getBottom()); - contentScrollView.invalidate(); - } + onScrollChangedListener = () -> { + runShadowAnimation(0, titleTextView != null && contentScrollView.getScrollY() > scrollContainer.getTop()); + runShadowAnimation(1, buttonsLayout != null && contentScrollView.getScrollY() + contentScrollView.getHeight() < scrollContainer.getBottom()); + contentScrollView.invalidate(); }; contentScrollView.getViewTreeObserver().addOnScrollChangedListener(onScrollChangedListener); } @@ -465,14 +454,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback { cell.setTextAndIcon(items[a], itemIcons != null ? itemIcons[a] : 0); scrollContainer.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); cell.setTag(a); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (onClickListener != null) { - onClickListener.onClick(AlertDialog.this, (Integer) v.getTag()); - } - dismiss(); + cell.setOnClickListener(v -> { + if (onClickListener != null) { + onClickListener.onClick(AlertDialog.this, (Integer) v.getTag()); } + dismiss(); }); } } @@ -537,6 +523,32 @@ public class AlertDialog extends Dialog implements Drawable.Callback { } } } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int totalWidth = 0; + int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); + int count = getChildCount(); + for (int a = 0; a < count; a++) { + View child = getChildAt(a); + if (child instanceof TextView && child.getTag() != null) { + totalWidth += child.getMeasuredWidth(); + } + } + if (totalWidth > availableWidth) { + View negative = findViewWithTag(BUTTON_NEGATIVE); + View neuntral = findViewWithTag(BUTTON_NEUTRAL); + if (negative != null && neuntral != null) { + if (negative.getMeasuredWidth() < neuntral.getMeasuredWidth()) { + neuntral.measure(MeasureSpec.makeMeasureSpec(neuntral.getMeasuredWidth() - (totalWidth - availableWidth), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(neuntral.getMeasuredHeight(), MeasureSpec.EXACTLY)); + } else { + negative.measure(MeasureSpec.makeMeasureSpec(negative.getMeasuredWidth() - (totalWidth - availableWidth), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(negative.getMeasuredHeight(), MeasureSpec.EXACTLY)); + } + } + } + } }; buttonsLayout.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); containerView.addView(buttonsLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52)); @@ -561,15 +573,12 @@ public class AlertDialog extends Dialog implements Drawable.Callback { textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable()); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); buttonsLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 36, Gravity.TOP | Gravity.RIGHT)); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (positiveButtonListener != null) { - positiveButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_POSITIVE); - } - if (dismissDialogByButtons) { - dismiss(); - } + textView.setOnClickListener(v -> { + if (positiveButtonListener != null) { + positiveButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_POSITIVE); + } + if (dismissDialogByButtons) { + dismiss(); } }); } @@ -588,21 +597,18 @@ public class AlertDialog extends Dialog implements Drawable.Callback { textView.setTextColor(getThemeColor(Theme.key_dialogButton)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); -// textView.setLines(1); -// textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(true); textView.setText(negativeButtonText.toString().toUpperCase()); textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable()); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); buttonsLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 36, Gravity.TOP | Gravity.RIGHT)); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (negativeButtonListener != null) { - negativeButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_NEGATIVE); - } - if (dismissDialogByButtons) { - cancel(); - } + textView.setOnClickListener(v -> { + if (negativeButtonListener != null) { + negativeButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_NEGATIVE); + } + if (dismissDialogByButtons) { + cancel(); } }); } @@ -621,21 +627,18 @@ public class AlertDialog extends Dialog implements Drawable.Callback { textView.setTextColor(getThemeColor(Theme.key_dialogButton)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); -// textView.setLines(1); -// textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(true); textView.setText(neutralButtonText.toString().toUpperCase()); textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable()); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); buttonsLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 36, Gravity.TOP | Gravity.LEFT)); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (neutralButtonListener != null) { - neutralButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_NEGATIVE); - } - if (dismissDialogByButtons) { - dismiss(); - } + textView.setOnClickListener(v -> { + if (neutralButtonListener != null) { + neutralButtonListener.onClick(AlertDialog.this, Dialog.BUTTON_NEGATIVE); + } + if (dismissDialogByButtons) { + dismiss(); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 8eb102700..56484b8b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -369,15 +369,12 @@ public class BaseFragment { try { visibleDialog = dialog; visibleDialog.setCanceledOnTouchOutside(true); - visibleDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - if (onDismissListener != null) { - onDismissListener.onDismiss(dialog); - } - onDialogDismiss(visibleDialog); - visibleDialog = null; + visibleDialog.setOnDismissListener(dialog1 -> { + if (onDismissListener != null) { + onDismissListener.onDismiss(dialog1); } + onDialogDismiss(visibleDialog); + visibleDialog = null; }); visibleDialog.show(); return visibleDialog; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index fe0ff71f5..71285b722 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -12,7 +12,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; @@ -101,12 +100,7 @@ public class BottomSheet extends Dialog { private ArrayList itemViews = new ArrayList<>(); - private Runnable dismissRunnable = new Runnable() { - @Override - public void run() { - dismiss(); - } - }; + private Runnable dismissRunnable = this::dismiss; private BottomSheetDelegateInterface delegate; @@ -574,14 +568,10 @@ public class BottomSheet extends Dialog { focusable = needFocus; if (Build.VERSION.SDK_INT >= 21) { container.setFitsSystemWindows(true); - container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { - @SuppressLint("NewApi") - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - lastInsets = insets; - v.requestLayout(); - return insets.consumeSystemWindowInsets(); - } + container.setOnApplyWindowInsetsListener((v, insets) -> { + lastInsets = insets; + v.requestLayout(); + return insets.consumeSystemWindowInsets(); }); container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } @@ -631,12 +621,7 @@ public class BottomSheet extends Dialog { titleView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(8)); titleView.setGravity(Gravity.CENTER_VERTICAL); containerView.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); - titleView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + titleView.setOnTouchListener((v, event) -> true); topOffset += 48; } if (customView != null) { @@ -658,12 +643,7 @@ public class BottomSheet extends Dialog { containerView.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP, 0, topOffset, 0, 0)); topOffset += 48; cell.setTag(a); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismissWithButtonClick((Integer) v.getTag()); - } - }); + cell.setOnClickListener(v -> dismissWithButtonClick((Integer) v.getTag())); itemViews.add(cell); } } @@ -870,14 +850,11 @@ public class BottomSheet extends Dialog { if (onClickListener != null) { onClickListener.onClick(BottomSheet.this, item); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - BottomSheet.super.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + AndroidUtilities.runOnUIThread(() -> { + try { + BottomSheet.super.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -923,14 +900,11 @@ public class BottomSheet extends Dialog { public void onAnimationEnd(Animator animation) { if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { currentSheetAnimation = null; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - dismissInternal(); - } catch (Exception e) { - FileLog.e(e); - } + AndroidUtilities.runOnUIThread(() -> { + try { + dismissInternal(); + } catch (Exception e) { + FileLog.e(e); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java index df7588b17..d28544428 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java @@ -78,17 +78,13 @@ public class DrawerLayoutContainer extends FrameLayout { if (Build.VERSION.SDK_INT >= 21) { setFitsSystemWindows(true); - setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener() { - @SuppressLint("NewApi") - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - final DrawerLayoutContainer drawerLayout = (DrawerLayoutContainer) v; - AndroidUtilities.statusBarHeight = insets.getSystemWindowInsetTop(); - lastInsets = insets; - drawerLayout.setWillNotDraw(insets.getSystemWindowInsetTop() <= 0 && getBackground() == null); - drawerLayout.requestLayout(); - return insets.consumeSystemWindowInsets(); - } + setOnApplyWindowInsetsListener((v, insets) -> { + final DrawerLayoutContainer drawerLayout = (DrawerLayoutContainer) v; + AndroidUtilities.statusBarHeight = insets.getSystemWindowInsetTop(); + lastInsets = insets; + drawerLayout.setWillNotDraw(insets.getSystemWindowInsetTop() <= 0 && getBackground() == null); + drawerLayout.requestLayout(); + return insets.consumeSystemWindowInsets(); }); setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index df99d9bc0..116321bcf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -71,7 +71,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; public class Theme { @@ -818,7 +817,9 @@ public class Theme { public static final String key_chat_inContactNameText = "chat_inContactNameText"; public static final String key_chat_outContactNameText = "chat_outContactNameText"; public static final String key_chat_inContactPhoneText = "chat_inContactPhoneText"; + public static final String key_chat_inContactPhoneSelectedText = "chat_inContactPhoneSelectedText"; public static final String key_chat_outContactPhoneText = "chat_outContactPhoneText"; + public static final String key_chat_outContactPhoneSelectedText = "chat_outContactPhoneText"; public static final String key_chat_mediaProgress = "chat_mediaProgress"; public static final String key_chat_inAudioProgress = "chat_inAudioProgress"; public static final String key_chat_outAudioProgress = "chat_outAudioProgress"; @@ -832,7 +833,9 @@ public class Theme { public static final String key_chat_inTimeSelectedText = "chat_inTimeSelectedText"; public static final String key_chat_outTimeSelectedText = "chat_outTimeSelectedText"; public static final String key_chat_inAudioPerfomerText = "chat_inAudioPerfomerText"; + public static final String key_chat_inAudioPerfomerSelectedText = "chat_inAudioPerfomerSelectedText"; public static final String key_chat_outAudioPerfomerText = "chat_outAudioPerfomerText"; + public static final String key_chat_outAudioPerfomerSelectedText = "chat_outAudioPerfomerSelectedText"; public static final String key_chat_inAudioTitleText = "chat_inAudioTitleText"; public static final String key_chat_outAudioTitleText = "chat_outAudioTitleText"; public static final String key_chat_inAudioDurationText = "chat_inAudioDurationText"; @@ -1411,7 +1414,9 @@ public class Theme { defaultColors.put(key_chat_inContactNameText, 0xff4e9ad4); defaultColors.put(key_chat_outContactNameText, 0xff55ab4f); defaultColors.put(key_chat_inContactPhoneText, 0xff2f3438); + defaultColors.put(key_chat_inContactPhoneSelectedText, 0xff2f3438); defaultColors.put(key_chat_outContactPhoneText, 0xff354234); + defaultColors.put(key_chat_outContactPhoneSelectedText, 0xff354234); defaultColors.put(key_chat_mediaProgress, 0xffffffff); defaultColors.put(key_chat_inAudioProgress, 0xffffffff); defaultColors.put(key_chat_outAudioProgress, 0xffefffde); @@ -1425,7 +1430,9 @@ public class Theme { defaultColors.put(key_chat_inTimeSelectedText, 0xff89b4c1); defaultColors.put(key_chat_outTimeSelectedText, 0xff70b15c); defaultColors.put(key_chat_inAudioPerfomerText, 0xff2f3438); + defaultColors.put(key_chat_inAudioPerfomerSelectedText, 0xff2f3438); defaultColors.put(key_chat_outAudioPerfomerText, 0xff354234); + defaultColors.put(key_chat_outAudioPerfomerSelectedText, 0xff354234); defaultColors.put(key_chat_inAudioTitleText, 0xff4e9ad4); defaultColors.put(key_chat_outAudioTitleText, 0xff55ab4f); defaultColors.put(key_chat_inAudioDurationText, 0xffa1aab3); @@ -1799,12 +1806,7 @@ public class Theme { currentDayTheme = applyingTheme; } applyTheme(applyingTheme, false, false, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkAutoNightThemeConditions(); - } - }); + AndroidUtilities.runOnUIThread(Theme::checkAutoNightThemeConditions); } private static Method StateListDrawable_getStateDrawableMethod; @@ -2208,16 +2210,13 @@ public class Theme { } private static void sortThemes() { - Collections.sort(themes, new Comparator() { - @Override - public int compare(ThemeInfo o1, ThemeInfo o2) { - if (o1.pathToFile == null && o1.assetName == null) { - return -1; - } else if (o2.pathToFile == null && o2.assetName == null) { - return 1; - } - return o1.name.compareTo(o2.name); + Collections.sort(themes, (o1, o2) -> { + if (o1.pathToFile == null && o1.assetName == null) { + return -1; + } else if (o2.pathToFile == null && o2.assetName == null) { + return 1; } + return o1.name.compareTo(o2.name); }); } @@ -2315,12 +2314,7 @@ public class Theme { applyDialogsTheme(); applyProfileTheme(); applyChatTheme(false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewTheme, nightTheme); - } - }); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewTheme, nightTheme)); } catch (Exception e) { FileLog.e(e); } @@ -3251,14 +3245,14 @@ public class Theme { for (int a = 0; a < 2; a++) { setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][0], getColor(key_chat_outLoader), false); - setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][0], getColor(key_chat_outBubble), true); + setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][0], getColor(key_chat_outMediaIcon), true); setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][1], getColor(key_chat_outLoaderSelected), false); - setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][1], getColor(key_chat_outBubbleSelected), true); + setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][1], getColor(key_chat_outMediaIconSelected), true); setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][0], getColor(key_chat_inLoader), false); - setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][0], getColor(key_chat_inBubble), true); + setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][0], getColor(key_chat_inMediaIcon), true); setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][1], getColor(key_chat_inLoaderSelected), false); - setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][1], getColor(key_chat_inBubbleSelected), true); + setCombinedDrawableColor(chat_fileMiniStatesDrawable[2 + a][1], getColor(key_chat_inMediaIconSelected), true); setCombinedDrawableColor(chat_fileMiniStatesDrawable[4 + a][0], getColor(key_chat_mediaLoaderPhoto), false); setCombinedDrawableColor(chat_fileMiniStatesDrawable[4 + a][0], getColor(key_chat_mediaLoaderPhotoIcon), true); @@ -3408,6 +3402,9 @@ public class Theme { } public static Drawable getThemedDrawable(Context context, int resId, String key) { + if (context == null) { + return null; + } Drawable drawable = context.getResources().getDrawable(resId).mutate(); drawable.setColorFilter(new PorterDuffColorFilter(getColor(key), PorterDuff.Mode.MULTIPLY)); return drawable; @@ -3627,87 +3624,81 @@ public class Theme { if (wallpaper != null) { return; } - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - synchronized (wallpaperSync) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean overrideTheme = preferences.getBoolean("overrideThemeWallpaper", false); - if (!overrideTheme) { - Integer backgroundColor = currentColors.get(key_chat_wallpaper); - if (backgroundColor != null) { - wallpaper = new ColorDrawable(backgroundColor); - isCustomTheme = true; - } else if (themedWallpaperFileOffset > 0 && (currentTheme.pathToFile != null || currentTheme.assetName != null)) { - FileInputStream stream = null; + Utilities.searchQueue.postRunnable(() -> { + synchronized (wallpaperSync) { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + boolean overrideTheme = preferences.getBoolean("overrideThemeWallpaper", false); + if (!overrideTheme) { + Integer backgroundColor = currentColors.get(key_chat_wallpaper); + if (backgroundColor != null) { + wallpaper = new ColorDrawable(backgroundColor); + isCustomTheme = true; + } else if (themedWallpaperFileOffset > 0 && (currentTheme.pathToFile != null || currentTheme.assetName != null)) { + FileInputStream stream = null; + try { + int currentPosition = 0; + File file; + if (currentTheme.assetName != null) { + file = Theme.getAssetFile(currentTheme.assetName); + } else { + file = new File(currentTheme.pathToFile); + } + stream = new FileInputStream(file); + stream.getChannel().position(themedWallpaperFileOffset); + Bitmap bitmap = BitmapFactory.decodeStream(stream); + if (bitmap != null) { + themedWallpaper = wallpaper = new BitmapDrawable(bitmap); + isCustomTheme = true; + } + } catch (Throwable e) { + FileLog.e(e); + } finally { try { - int currentPosition = 0; - File file; - if (currentTheme.assetName != null) { - file = Theme.getAssetFile(currentTheme.assetName); - } else { - file = new File(currentTheme.pathToFile); + if (stream != null) { + stream.close(); } - stream = new FileInputStream(file); - stream.getChannel().position(themedWallpaperFileOffset); - Bitmap bitmap = BitmapFactory.decodeStream(stream); - if (bitmap != null) { - themedWallpaper = wallpaper = new BitmapDrawable(bitmap); - isCustomTheme = true; - } - } catch (Throwable e) { + } catch (Exception e) { FileLog.e(e); - } finally { - try { - if (stream != null) { - stream.close(); - } - } catch (Exception e) { - FileLog.e(e); - } } } } - if (wallpaper == null) { - int selectedColor = 0; - try { - preferences = MessagesController.getGlobalMainSettings(); - int selectedBackground = preferences.getInt("selectedBackground", 1000001); - selectedColor = preferences.getInt("selectedColor", 0); - if (selectedColor == 0) { - if (selectedBackground == 1000001) { + } + if (wallpaper == null) { + int selectedColor = 0; + try { + preferences = MessagesController.getGlobalMainSettings(); + int selectedBackground = preferences.getInt("selectedBackground", 1000001); + selectedColor = preferences.getInt("selectedColor", 0); + if (selectedColor == 0) { + if (selectedBackground == 1000001) { + wallpaper = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.background_hd); + isCustomTheme = false; + } else { + File toFile = new File(ApplicationLoader.getFilesDirFixed(), "wallpaper.jpg"); + if (toFile.exists()) { + wallpaper = Drawable.createFromPath(toFile.getAbsolutePath()); + isCustomTheme = true; + } else { wallpaper = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.background_hd); isCustomTheme = false; - } else { - File toFile = new File(ApplicationLoader.getFilesDirFixed(), "wallpaper.jpg"); - if (toFile.exists()) { - wallpaper = Drawable.createFromPath(toFile.getAbsolutePath()); - isCustomTheme = true; - } else { - wallpaper = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.background_hd); - isCustomTheme = false; - } } } - } catch (Throwable throwable) { - //ignore - } - if (wallpaper == null) { - if (selectedColor == 0) { - selectedColor = -2693905; - } - wallpaper = new ColorDrawable(selectedColor); } + } catch (Throwable throwable) { + //ignore } - calcBackgroundColor(wallpaper, 1); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - applyChatServiceMessageColor(); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); + if (wallpaper == null) { + if (selectedColor == 0) { + selectedColor = -2693905; } - }); + wallpaper = new ColorDrawable(selectedColor); + } } + calcBackgroundColor(wallpaper, 1); + AndroidUtilities.runOnUIThread(() -> { + applyChatServiceMessageColor(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); + }); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java index 4d5c700ac..a9f4096bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java @@ -16,7 +16,6 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.RecyclerListView; @@ -77,12 +76,9 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap } catch (Exception e) { FileLog.e(e); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - lastSearchLocation = null; - searchPlacesWithQuery(query, coordinate, true); - } + AndroidUtilities.runOnUIThread(() -> { + lastSearchLocation = null; + searchPlacesWithQuery(query, coordinate, true); }); } }, 200, 500); @@ -96,23 +92,17 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap searchingUser = true; TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); req.username = MessagesController.getInstance(currentAccount).venueSearchBot; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - MessagesController.getInstance(currentAccount).putChats(res.chats, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - Location coord = lastSearchLocation; - lastSearchLocation = null; - searchPlacesWithQuery(lastSearchQuery, coord, false); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + Location coord = lastSearchLocation; + lastSearchLocation = null; + searchPlacesWithQuery(lastSearchQuery, coord, false); + }); } }); } @@ -159,45 +149,37 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap req.peer = new TLRPC.TL_inputPeerEmpty(); } - currentRequestNum = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - currentRequestNum = 0; - searching = false; - places.clear(); - iconUrls.clear(); + currentRequestNum = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + currentRequestNum = 0; + searching = false; + places.clear(); + iconUrls.clear(); - if (error != null) { - if (delegate != null) { - delegate.didLoadedSearchResult(places); - } - } else { - TLRPC.messages_BotResults res = (TLRPC.messages_BotResults) response; - for (int a = 0, size = res.results.size(); a < size; a++) { - TLRPC.BotInlineResult result = res.results.get(a); - if (!"venue".equals(result.type) || !(result.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue)) { - continue; - } - TLRPC.TL_botInlineMessageMediaVenue mediaVenue = (TLRPC.TL_botInlineMessageMediaVenue) result.send_message; - iconUrls.add("https://ss3.4sqi.net/img/categories_v2/" + mediaVenue.venue_type + "_64.png"); - TLRPC.TL_messageMediaVenue venue = new TLRPC.TL_messageMediaVenue(); - venue.geo = mediaVenue.geo; - venue.address = mediaVenue.address; - venue.title = mediaVenue.title; - venue.venue_type = mediaVenue.venue_type; - venue.venue_id = mediaVenue.venue_id; - venue.provider = mediaVenue.provider; - places.add(venue); - } - } - notifyDataSetChanged(); + if (error != null) { + if (delegate != null) { + delegate.didLoadedSearchResult(places); + } + } else { + TLRPC.messages_BotResults res = (TLRPC.messages_BotResults) response; + for (int a = 0, size = res.results.size(); a < size; a++) { + TLRPC.BotInlineResult result = res.results.get(a); + if (!"venue".equals(result.type) || !(result.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue)) { + continue; } - }); + TLRPC.TL_botInlineMessageMediaVenue mediaVenue = (TLRPC.TL_botInlineMessageMediaVenue) result.send_message; + iconUrls.add("https://ss3.4sqi.net/img/categories_v2/" + mediaVenue.venue_type + "_64.png"); + TLRPC.TL_messageMediaVenue venue = new TLRPC.TL_messageMediaVenue(); + venue.geo = mediaVenue.geo; + venue.address = mediaVenue.address; + venue.title = mediaVenue.title; + venue.venue_type = mediaVenue.venue_type; + venue.venue_id = mediaVenue.venue_id; + venue.provider = mediaVenue.provider; + places.add(venue); + } } - }); + notifyDataSetChanged(); + })); notifyDataSetChanged(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index 4f6fe4f5f..0cfa51cd9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -198,14 +198,11 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { textView.setText(LocaleController.getString("RecentlyViewedHide", R.string.RecentlyViewedHide)); textView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL); headerCell.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, 17, 15, 17, 0)); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - MessagesController.getInstance(currentAccount).hintDialogs.clear(); - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - preferences.edit().remove("installReferer").commit(); - notifyDataSetChanged(); - } + textView.setOnClickListener(view1 -> { + MessagesController.getInstance(currentAccount).hintDialogs.clear(); + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + preferences.edit().remove("installReferer").commit(); + notifyDataSetChanged(); }); view = headerCell; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index b00700c4c..2990e8c99 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -35,7 +35,6 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -49,7 +48,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Locale; import java.util.Timer; @@ -245,45 +243,37 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (delegate != null) { delegate.searchStateChanged(true); } - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (currentReqId == lastReqId) { - if (error == null) { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - MessagesController.getInstance(currentAccount).putChats(res.chats, false); - if (req.offset_id == 0) { - searchResultMessages.clear(); - } - for (int a = 0; a < res.messages.size(); a++) { - TLRPC.Message message = res.messages.get(a); - searchResultMessages.add(new MessageObject(currentAccount, message, false)); - long dialog_id = MessageObject.getDialogId(message); - ConcurrentHashMap read_max = message.out ? MessagesController.getInstance(currentAccount).dialogs_read_outbox_max : MessagesController.getInstance(currentAccount).dialogs_read_inbox_max; - Integer value = read_max.get(dialog_id); - if (value == null) { - value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, dialog_id); - read_max.put(dialog_id, value); - } - message.unread = value < message.id; - } - messagesSearchEndReached = res.messages.size() != 20; - notifyDataSetChanged(); - } - } - if (delegate != null) { - delegate.searchStateChanged(false); - } - reqId = 0; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + if (req.offset_id == 0) { + searchResultMessages.clear(); } - }); + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + searchResultMessages.add(new MessageObject(currentAccount, message, false)); + long dialog_id = MessageObject.getDialogId(message); + ConcurrentHashMap read_max = message.out ? MessagesController.getInstance(currentAccount).dialogs_read_outbox_max : MessagesController.getInstance(currentAccount).dialogs_read_inbox_max; + Integer value = read_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance(currentAccount).getDialogReadMax(message.out, dialog_id); + read_max.put(dialog_id, value); + } + message.unread = value < message.id; + } + messagesSearchEndReached = res.messages.size() != 20; + notifyDataSetChanged(); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + if (delegate != null) { + delegate.searchStateChanged(false); + } + reqId = 0; + }), ConnectionsManager.RequestFlagFailOnServerErrors); } public boolean hasRecentRearch() { @@ -295,126 +285,115 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } public void loadRecentSearch() { - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT did, date FROM search_recent WHERE 1"); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT did, date FROM search_recent WHERE 1"); - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList encryptedToLoad = new ArrayList<>(); - ArrayList encUsers = new ArrayList<>(); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedToLoad = new ArrayList<>(); + ArrayList encUsers = new ArrayList<>(); - final ArrayList arrayList = new ArrayList<>(); - final LongSparseArray hashMap = new LongSparseArray<>(); - while (cursor.next()) { - long did = cursor.longValue(0); + final ArrayList arrayList = new ArrayList<>(); + final LongSparseArray hashMap = new LongSparseArray<>(); + while (cursor.next()) { + long did = cursor.longValue(0); - boolean add = false; - int lower_id = (int) did; - int high_id = (int) (did >> 32); - if (lower_id != 0) { - if (high_id == 1) { - if (dialogsType == 0 && !chatsToLoad.contains(lower_id)) { - chatsToLoad.add(lower_id); + boolean add = false; + int lower_id = (int) did; + int high_id = (int) (did >> 32); + if (lower_id != 0) { + if (high_id == 1) { + if (dialogsType == 0 && !chatsToLoad.contains(lower_id)) { + chatsToLoad.add(lower_id); + add = true; + } + } else { + if (lower_id > 0) { + if (dialogsType != 2 && !usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); add = true; } } else { - if (lower_id > 0) { - if (dialogsType != 2 && !usersToLoad.contains(lower_id)) { - usersToLoad.add(lower_id); - add = true; - } - } else { - if (!chatsToLoad.contains(-lower_id)) { - chatsToLoad.add(-lower_id); - add = true; - } + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + add = true; } } - } else if (dialogsType == 0) { - if (!encryptedToLoad.contains(high_id)) { - encryptedToLoad.add(high_id); - add = true; - } } - if (add) { - RecentSearchObject recentSearchObject = new RecentSearchObject(); - recentSearchObject.did = did; - recentSearchObject.date = cursor.intValue(1); - arrayList.add(recentSearchObject); - hashMap.put(recentSearchObject.did, recentSearchObject); + } else if (dialogsType == 0) { + if (!encryptedToLoad.contains(high_id)) { + encryptedToLoad.add(high_id); + add = true; } } - cursor.dispose(); - - - ArrayList users = new ArrayList<>(); - - if (!encryptedToLoad.isEmpty()) { - ArrayList encryptedChats = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); - for (int a = 0; a < encryptedChats.size(); a++) { - hashMap.get((long) encryptedChats.get(a).id << 32).object = encryptedChats.get(a); - } + if (add) { + RecentSearchObject recentSearchObject = new RecentSearchObject(); + recentSearchObject.did = did; + recentSearchObject.date = cursor.intValue(1); + arrayList.add(recentSearchObject); + hashMap.put(recentSearchObject.did, recentSearchObject); } - - if (!chatsToLoad.isEmpty()) { - ArrayList chats = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).getChatsInternal(TextUtils.join(",", chatsToLoad), chats); - for (int a = 0; a < chats.size(); a++) { - TLRPC.Chat chat = chats.get(a); - long did; - if (chat.id > 0) { - did = -chat.id; - } else { - did = AndroidUtilities.makeBroadcastId(chat.id); - } - if (chat.migrated_to != null) { - RecentSearchObject recentSearchObject = hashMap.get(did); - hashMap.remove(did); - if (recentSearchObject != null) { - arrayList.remove(recentSearchObject); - } - } else { - hashMap.get(did).object = chat; - } - } - } - - if (!usersToLoad.isEmpty()) { - MessagesStorage.getInstance(currentAccount).getUsersInternal(TextUtils.join(",", usersToLoad), users); - for (int a = 0; a < users.size(); a++) { - TLRPC.User user = users.get(a); - RecentSearchObject recentSearchObject = hashMap.get((long) user.id); - if (recentSearchObject != null) { - recentSearchObject.object = user; - } - } - } - - Collections.sort(arrayList, new Comparator() { - @Override - public int compare(RecentSearchObject lhs, RecentSearchObject rhs) { - if (lhs.date < rhs.date) { - return 1; - } else if (lhs.date > rhs.date) { - return -1; - } else { - return 0; - } - } - }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - setRecentSearch(arrayList, hashMap); - } - }); - } catch (Exception e) { - FileLog.e(e); } + cursor.dispose(); + + + ArrayList users = new ArrayList<>(); + + if (!encryptedToLoad.isEmpty()) { + ArrayList encryptedChats = new ArrayList<>(); + MessagesStorage.getInstance(currentAccount).getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); + for (int a = 0; a < encryptedChats.size(); a++) { + hashMap.get((long) encryptedChats.get(a).id << 32).object = encryptedChats.get(a); + } + } + + if (!chatsToLoad.isEmpty()) { + ArrayList chats = new ArrayList<>(); + MessagesStorage.getInstance(currentAccount).getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + long did; + if (chat.id > 0) { + did = -chat.id; + } else { + did = AndroidUtilities.makeBroadcastId(chat.id); + } + if (chat.migrated_to != null) { + RecentSearchObject recentSearchObject = hashMap.get(did); + hashMap.remove(did); + if (recentSearchObject != null) { + arrayList.remove(recentSearchObject); + } + } else { + hashMap.get(did).object = chat; + } + } + } + + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance(currentAccount).getUsersInternal(TextUtils.join(",", usersToLoad), users); + for (int a = 0; a < users.size(); a++) { + TLRPC.User user = users.get(a); + RecentSearchObject recentSearchObject = hashMap.get((long) user.id); + if (recentSearchObject != null) { + recentSearchObject.object = user; + } + } + } + + Collections.sort(arrayList, (lhs, rhs) -> { + if (lhs.date < rhs.date) { + return 1; + } else if (lhs.date > rhs.date) { + return -1; + } else { + return 0; + } + }); + AndroidUtilities.runOnUIThread(() -> setRecentSearch(arrayList, hashMap)); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -432,19 +411,16 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { recentSearchObject.object = object; recentSearchObject.date = (int) (System.currentTimeMillis() / 1000); notifyDataSetChanged(); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLitePreparedStatement state = MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("REPLACE INTO search_recent VALUES(?, ?)"); - state.requery(); - state.bindLong(1, did); - state.bindInteger(2, (int) (System.currentTimeMillis() / 1000)); - state.step(); - state.dispose(); - } catch (Exception e) { - FileLog.e(e); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + SQLitePreparedStatement state = MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("REPLACE INTO search_recent VALUES(?, ?)"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, (int) (System.currentTimeMillis() / 1000)); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -453,14 +429,11 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { recentSearchObjectsById = new LongSparseArray<>(); recentSearchObjects = new ArrayList<>(); notifyDataSetChanged(); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM search_recent WHERE 1").stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM search_recent WHERE 1").stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } @@ -489,344 +462,335 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { if (needMessagesSearch == 2) { return; } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - String savedMessages = LocaleController.getString("SavedMessages", R.string.SavedMessages).toLowerCase(); - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - lastSearchId = -1; - updateSearchResults(new ArrayList(), new ArrayList(), new ArrayList(), lastSearchId); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + String savedMessages = LocaleController.getString("SavedMessages", R.string.SavedMessages).toLowerCase(); + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + lastSearchId = -1; + updateSearchResults(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), lastSearchId); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); - ArrayList encryptedToLoad = new ArrayList<>(); - ArrayList encUsers = new ArrayList<>(); - int resultCount = 0; + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedToLoad = new ArrayList<>(); + ArrayList encUsers = new ArrayList<>(); + int resultCount = 0; - LongSparseArray dialogsResult = new LongSparseArray<>(); - SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 600"); - while (cursor.next()) { - long id = cursor.longValue(0); - DialogSearchResult dialogSearchResult = new DialogSearchResult(); - dialogSearchResult.date = cursor.intValue(1); - dialogsResult.put(id, dialogSearchResult); + LongSparseArray dialogsResult = new LongSparseArray<>(); + SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 600"); + while (cursor.next()) { + long id = cursor.longValue(0); + DialogSearchResult dialogSearchResult = new DialogSearchResult(); + dialogSearchResult.date = cursor.intValue(1); + dialogsResult.put(id, dialogSearchResult); - int lower_id = (int) id; - int high_id = (int) (id >> 32); - if (lower_id != 0) { - if (high_id == 1) { - if (dialogsType == 0 && !chatsToLoad.contains(lower_id)) { - chatsToLoad.add(lower_id); + int lower_id = (int) id; + int high_id = (int) (id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + if (dialogsType == 0 && !chatsToLoad.contains(lower_id)) { + chatsToLoad.add(lower_id); + } + } else { + if (lower_id > 0) { + if (dialogsType != 2 && !usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); } } else { - if (lower_id > 0) { - if (dialogsType != 2 && !usersToLoad.contains(lower_id)) { - usersToLoad.add(lower_id); - } - } else { - if (!chatsToLoad.contains(-lower_id)) { - chatsToLoad.add(-lower_id); - } + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); } } - } else if (dialogsType == 0) { - if (!encryptedToLoad.contains(high_id)) { - encryptedToLoad.add(high_id); + } + } else if (dialogsType == 0) { + if (!encryptedToLoad.contains(high_id)) { + encryptedToLoad.add(high_id); + } + } + } + cursor.dispose(); + + if (savedMessages.startsWith(search1)) { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + DialogSearchResult dialogSearchResult = new DialogSearchResult(); + dialogSearchResult.date = Integer.MAX_VALUE; + dialogSearchResult.name = savedMessages; + dialogSearchResult.object = user; + dialogsResult.put((long) user.id, dialogSearchResult); + resultCount++; + } + + if (!usersToLoad.isEmpty()) { + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, status, name FROM users WHERE uid IN(%s)", TextUtils.join(",", usersToLoad))); + while (cursor.next()) { + String name = cursor.stringValue(2); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 3); + } + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + if (found != 0) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + DialogSearchResult dialogSearchResult = dialogsResult.get((long) user.id); + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + if (found == 1) { + dialogSearchResult.name = AndroidUtilities.generateSearchName(user.first_name, user.last_name, q); + } else { + dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); + } + dialogSearchResult.object = user; + resultCount++; + } + break; } } } cursor.dispose(); - - if (savedMessages.startsWith(search1)) { - TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); - DialogSearchResult dialogSearchResult = new DialogSearchResult(); - dialogSearchResult.date = Integer.MAX_VALUE; - dialogSearchResult.name = savedMessages; - dialogSearchResult.object = user; - dialogsResult.put((long) user.id, dialogSearchResult); - resultCount++; - } - - if (!usersToLoad.isEmpty()) { - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, status, name FROM users WHERE uid IN(%s)", TextUtils.join(",", usersToLoad))); - while (cursor.next()) { - String name = cursor.stringValue(2); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - String username = null; - int usernamePos = name.lastIndexOf(";;;"); - if (usernamePos != -1) { - username = name.substring(usernamePos + 3); - } - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (username != null && username.startsWith(q)) { - found = 2; - } - if (found != 0) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - DialogSearchResult dialogSearchResult = dialogsResult.get((long) user.id); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - if (found == 1) { - dialogSearchResult.name = AndroidUtilities.generateSearchName(user.first_name, user.last_name, q); - } else { - dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); - } - dialogSearchResult.object = user; - resultCount++; - } - break; - } - } - } - cursor.dispose(); - } - - if (!chatsToLoad.isEmpty()) { - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, name FROM chats WHERE uid IN(%s)", TextUtils.join(",", chatsToLoad))); - while (cursor.next()) { - String name = cursor.stringValue(1); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - if (!(chat == null || chat.deactivated || ChatObject.isChannel(chat) && ChatObject.isNotInChat(chat))) { - long dialog_id; - if (chat.id > 0) { - dialog_id = -chat.id; - } else { - dialog_id = AndroidUtilities.makeBroadcastId(chat.id); - } - DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id); - dialogSearchResult.name = AndroidUtilities.generateSearchName(chat.title, null, q); - dialogSearchResult.object = chat; - resultCount++; - } - } - break; - } - } - } - cursor.dispose(); - } - - if (!encryptedToLoad.isEmpty()) { - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out, q.use_count, q.exchange_id, q.key_date, q.fprint, q.fauthkey, q.khash, q.in_seq_no, q.admin_id, q.mtproto_seq FROM enc_chats as q INNER JOIN users as u ON q.user = u.uid WHERE q.uid IN(%s)", TextUtils.join(",", encryptedToLoad))); - while (cursor.next()) { - String name = cursor.stringValue(1); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - String username = null; - int usernamePos = name.lastIndexOf(";;;"); - if (usernamePos != -1) { - username = name.substring(usernamePos + 2); - } - int found = 0; - for (int a = 0; a < search.length; a++) { - String q = search[a]; - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (username != null && username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - TLRPC.EncryptedChat chat = null; - TLRPC.User user = null; - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - chat = TLRPC.EncryptedChat.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - } - data = cursor.byteBufferValue(6); - if (data != null) { - user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - } - if (chat != null && user != null) { - DialogSearchResult dialogSearchResult = dialogsResult.get((long) chat.id << 32); - chat.user_id = cursor.intValue(2); - chat.a_or_b = cursor.byteArrayValue(3); - chat.auth_key = cursor.byteArrayValue(4); - chat.ttl = cursor.intValue(5); - chat.layer = cursor.intValue(8); - chat.seq_in = cursor.intValue(9); - chat.seq_out = cursor.intValue(10); - int use_count = cursor.intValue(11); - chat.key_use_count_in = (short) (use_count >> 16); - chat.key_use_count_out = (short) (use_count); - chat.exchange_id = cursor.longValue(12); - chat.key_create_date = cursor.intValue(13); - chat.future_key_fingerprint = cursor.longValue(14); - chat.future_auth_key = cursor.byteArrayValue(15); - chat.key_hash = cursor.byteArrayValue(16); - chat.in_seq_no = cursor.intValue(17); - int admin_id = cursor.intValue(18); - if (admin_id != 0) { - chat.admin_id = admin_id; - } - chat.mtproto_seq = cursor.intValue(19); - - if (user.status != null) { - user.status.expires = cursor.intValue(7); - } - if (found == 1) { - dialogSearchResult.name = new SpannableStringBuilder(ContactsController.formatName(user.first_name, user.last_name)); - ((SpannableStringBuilder) dialogSearchResult.name).setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_secretName)), 0, dialogSearchResult.name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } else { - dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); - } - dialogSearchResult.object = chat; - encUsers.add(user); - resultCount++; - } - break; - } - } - } - cursor.dispose(); - } - - ArrayList searchResults = new ArrayList<>(resultCount); - for (int a = 0; a < dialogsResult.size(); a++) { - DialogSearchResult dialogSearchResult = dialogsResult.valueAt(a); - if (dialogSearchResult.object != null && dialogSearchResult.name != null) { - searchResults.add(dialogSearchResult); - } - } - - Collections.sort(searchResults, new Comparator() { - @Override - public int compare(DialogSearchResult lhs, DialogSearchResult rhs) { - if (lhs.date < rhs.date) { - return 1; - } else if (lhs.date > rhs.date) { - return -1; - } - return 0; - } - }); - - ArrayList resultArray = new ArrayList<>(); - ArrayList resultArrayNames = new ArrayList<>(); - - for (int a = 0; a < searchResults.size(); a++) { - DialogSearchResult dialogSearchResult = searchResults.get(a); - resultArray.add(dialogSearchResult.object); - resultArrayNames.add(dialogSearchResult.name); - } - - if (dialogsType != 2) { - cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); - while (cursor.next()) { - int uid = cursor.intValue(3); - if (dialogsResult.indexOfKey((long) uid) >= 0) { - continue; - } - String name = cursor.stringValue(2); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - String username = null; - int usernamePos = name.lastIndexOf(";;;"); - if (usernamePos != -1) { - username = name.substring(usernamePos + 3); - } - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (username != null && username.startsWith(q)) { - found = 2; - } - if (found != 0) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray.add(user); - } - break; - } - } - } - cursor.dispose(); - } - - updateSearchResults(resultArray, resultArrayNames, encUsers, searchId); - } catch (Exception e) { - FileLog.e(e); } + + if (!chatsToLoad.isEmpty()) { + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, name FROM chats WHERE uid IN(%s)", TextUtils.join(",", chatsToLoad))); + while (cursor.next()) { + String name = cursor.stringValue(1); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + if (!(chat == null || chat.deactivated || ChatObject.isChannel(chat) && ChatObject.isNotInChat(chat))) { + long dialog_id; + if (chat.id > 0) { + dialog_id = -chat.id; + } else { + dialog_id = AndroidUtilities.makeBroadcastId(chat.id); + } + DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id); + dialogSearchResult.name = AndroidUtilities.generateSearchName(chat.title, null, q); + dialogSearchResult.object = chat; + resultCount++; + } + } + break; + } + } + } + cursor.dispose(); + } + + if (!encryptedToLoad.isEmpty()) { + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized(String.format(Locale.US, "SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out, q.use_count, q.exchange_id, q.key_date, q.fprint, q.fauthkey, q.khash, q.in_seq_no, q.admin_id, q.mtproto_seq FROM enc_chats as q INNER JOIN users as u ON q.user = u.uid WHERE q.uid IN(%s)", TextUtils.join(",", encryptedToLoad))); + while (cursor.next()) { + String name = cursor.stringValue(1); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 2); + } + int found = 0; + for (int a = 0; a < search.length; a++) { + String q = search[a]; + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + TLRPC.EncryptedChat chat = null; + TLRPC.User user = null; + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + chat = TLRPC.EncryptedChat.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + } + data = cursor.byteBufferValue(6); + if (data != null) { + user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + } + if (chat != null && user != null) { + DialogSearchResult dialogSearchResult = dialogsResult.get((long) chat.id << 32); + chat.user_id = cursor.intValue(2); + chat.a_or_b = cursor.byteArrayValue(3); + chat.auth_key = cursor.byteArrayValue(4); + chat.ttl = cursor.intValue(5); + chat.layer = cursor.intValue(8); + chat.seq_in = cursor.intValue(9); + chat.seq_out = cursor.intValue(10); + int use_count = cursor.intValue(11); + chat.key_use_count_in = (short) (use_count >> 16); + chat.key_use_count_out = (short) (use_count); + chat.exchange_id = cursor.longValue(12); + chat.key_create_date = cursor.intValue(13); + chat.future_key_fingerprint = cursor.longValue(14); + chat.future_auth_key = cursor.byteArrayValue(15); + chat.key_hash = cursor.byteArrayValue(16); + chat.in_seq_no = cursor.intValue(17); + int admin_id = cursor.intValue(18); + if (admin_id != 0) { + chat.admin_id = admin_id; + } + chat.mtproto_seq = cursor.intValue(19); + + if (user.status != null) { + user.status.expires = cursor.intValue(7); + } + if (found == 1) { + dialogSearchResult.name = new SpannableStringBuilder(ContactsController.formatName(user.first_name, user.last_name)); + ((SpannableStringBuilder) dialogSearchResult.name).setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_secretName)), 0, dialogSearchResult.name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); + } + dialogSearchResult.object = chat; + encUsers.add(user); + resultCount++; + } + break; + } + } + } + cursor.dispose(); + } + + ArrayList searchResults = new ArrayList<>(resultCount); + for (int a = 0; a < dialogsResult.size(); a++) { + DialogSearchResult dialogSearchResult = dialogsResult.valueAt(a); + if (dialogSearchResult.object != null && dialogSearchResult.name != null) { + searchResults.add(dialogSearchResult); + } + } + + Collections.sort(searchResults, (lhs, rhs) -> { + if (lhs.date < rhs.date) { + return 1; + } else if (lhs.date > rhs.date) { + return -1; + } + return 0; + }); + + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); + + for (int a = 0; a < searchResults.size(); a++) { + DialogSearchResult dialogSearchResult = searchResults.get(a); + resultArray.add(dialogSearchResult.object); + resultArrayNames.add(dialogSearchResult.name); + } + + if (dialogsType != 2) { + cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); + while (cursor.next()) { + int uid = cursor.intValue(3); + if (dialogsResult.indexOfKey((long) uid) >= 0) { + continue; + } + String name = cursor.stringValue(2); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 3); + } + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + if (found != 0) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(user); + } + break; + } + } + } + cursor.dispose(); + } + + updateSearchResults(resultArray, resultArrayNames, encUsers, searchId); + } catch (Exception e) { + FileLog.e(e); } }); } private void updateSearchResults(final ArrayList result, final ArrayList names, final ArrayList encUsers, final int searchId) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (searchId != lastSearchId) { - return; - } - for (int a = 0; a < result.size(); a++) { - TLObject obj = result.get(a); - if (obj instanceof TLRPC.User) { - TLRPC.User user = (TLRPC.User) obj; - MessagesController.getInstance(currentAccount).putUser(user, true); - } else if (obj instanceof TLRPC.Chat) { - TLRPC.Chat chat = (TLRPC.Chat) obj; - MessagesController.getInstance(currentAccount).putChat(chat, true); - } else if (obj instanceof TLRPC.EncryptedChat) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) obj; - MessagesController.getInstance(currentAccount).putEncryptedChat(chat, true); - } - } - MessagesController.getInstance(currentAccount).putUsers(encUsers, true); - searchResult = result; - searchResultNames = names; - searchAdapterHelper.mergeResults(searchResult); - notifyDataSetChanged(); + AndroidUtilities.runOnUIThread(() -> { + if (searchId != lastSearchId) { + return; } + for (int a = 0; a < result.size(); a++) { + TLObject obj = result.get(a); + if (obj instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) obj; + MessagesController.getInstance(currentAccount).putUser(user, true); + } else if (obj instanceof TLRPC.Chat) { + TLRPC.Chat chat = (TLRPC.Chat) obj; + MessagesController.getInstance(currentAccount).putChat(chat, true); + } else if (obj instanceof TLRPC.EncryptedChat) { + TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) obj; + MessagesController.getInstance(currentAccount).putEncryptedChat(chat, true); + } + } + MessagesController.getInstance(currentAccount).putUsers(encUsers, true); + searchResult = result; + searchResultNames = names; + searchAdapterHelper.mergeResults(searchResult); + notifyDataSetChanged(); }); } @@ -896,14 +860,11 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { FileLog.e(e); } searchDialogsInternal(query, searchId); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (needMessagesSearch != 2) { - searchAdapterHelper.queryServerSearch(query, true, true, true, true, 0, false); - } - searchMessagesInternal(query); + AndroidUtilities.runOnUIThread(() -> { + if (needMessagesSearch != 2) { + searchAdapterHelper.queryServerSearch(query, true, true, true, true, 0, false); } + searchMessagesInternal(query); }); } }, 200, 300); @@ -1056,22 +1017,16 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { horizontalListView.setLayoutManager(layoutManager); //horizontalListView.setDisallowInterceptTouchEvents(true); horizontalListView.setAdapter(new CategoryAdapterRecycler()); - horizontalListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (delegate != null) { - delegate.didPressedOnSubDialog((Integer) view.getTag()); - } + horizontalListView.setOnItemClickListener((view1, position) -> { + if (delegate != null) { + delegate.didPressedOnSubDialog((Integer) view1.getTag()); } }); - horizontalListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (delegate != null) { - delegate.needRemoveHint((Integer) view.getTag()); - } - return true; + horizontalListView.setOnItemLongClickListener((view12, position) -> { + if (delegate != null) { + delegate.needRemoveHint((Integer) view12.getTag()); } + return true; }); view = horizontalListView; innerListView = horizontalListView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java index aa5a28bbc..af4c008be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -29,7 +29,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { @@ -105,12 +104,9 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { switch (viewType) { case 0: profileCell = new DrawerProfileCell(mContext); - profileCell.setOnArrowClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - DrawerProfileCell drawerProfileCell = (DrawerProfileCell) v; - setAccountsShowed(drawerProfileCell.isAccountsShowed(), true); - } + profileCell.setOnArrowClickListener(v -> { + DrawerProfileCell drawerProfileCell = (DrawerProfileCell) v; + setAccountsShowed(drawerProfileCell.isAccountsShowed(), true); }); view = profileCell; break; @@ -200,18 +196,15 @@ public class DrawerLayoutAdapter extends RecyclerListView.SelectionAdapter { accountNumbers.add(a); } } - Collections.sort(accountNumbers, new Comparator() { - @Override - public int compare(Integer o1, Integer o2) { - long l1 = UserConfig.getInstance(o1).loginTime; - long l2 = UserConfig.getInstance(o2).loginTime; - if (l1 > l2) { - return 1; - } else if (l1 < l2) { - return -1; - } - return 0; + Collections.sort(accountNumbers, (o1, o2) -> { + long l1 = UserConfig.getInstance(o1).loginTime; + long l2 = UserConfig.getInstance(o2).loginTime; + if (l1 > l2) { + return 1; + } else if (l1 < l2) { + return -1; } + return 0; }); items.clear(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java index 34fd4b004..9e3f927c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java @@ -175,12 +175,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter { return; } pulledUp = true; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - notifyItemChanged(liveLocationType == 0 ? 2 : 3); - } - }); + AndroidUtilities.runOnUIThread(() -> notifyItemChanged(liveLocationType == 0 ? 2 : 3)); } public boolean isPulledUp() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java index 9c5d09326..e6bf29c78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -10,7 +10,6 @@ package org.telegram.ui.Adapters; import android.Manifest; import android.content.Context; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.location.Location; @@ -51,7 +50,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; public class MentionsAdapter extends RecyclerListView.SelectionAdapter { @@ -262,32 +260,23 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); builder.setMessage(LocaleController.getString("ShareYouLocationInline", R.string.ShareYouLocationInline)); final boolean buttonClicked[] = new boolean[1]; - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - buttonClicked[0] = true; - if (foundContextBotFinal != null) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putBoolean("inlinegeo_" + foundContextBotFinal.id, true).commit(); - checkLocationPermissionsOrStart(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + buttonClicked[0] = true; + if (foundContextBotFinal != null) { + SharedPreferences preferences1 = MessagesController.getNotificationsSettings(currentAccount); + preferences1.edit().putBoolean("inlinegeo_" + foundContextBotFinal.id, true).commit(); + checkLocationPermissionsOrStart(); } }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - buttonClicked[0] = true; + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + buttonClicked[0] = true; + onLocationUnavailable(); + }); + parentFragment.showDialog(builder.create(), dialog -> { + if (!buttonClicked[0]) { onLocationUnavailable(); } }); - parentFragment.showDialog(builder.create(), new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - if (!buttonClicked[0]) { - onLocationUnavailable(); - } - } - }); } else { checkLocationPermissionsOrStart(); } @@ -387,29 +376,21 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } else { TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); req.username = searchingContextUsername; - contextUsernameReqid = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (searchingContextUsername == null || !searchingContextUsername.equals(username)) { - return; - } - TLRPC.User user = null; - if (error == null) { - TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; - if (!res.users.isEmpty()) { - user = res.users.get(0); - messagesController.putUser(user, false); - messagesStorage.putUsersAndChats(res.users, null, true, true); - } - } - processFoundUser(user); - } - }); + contextUsernameReqid = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (searchingContextUsername == null || !searchingContextUsername.equals(username)) { + return; } - }); + TLRPC.User user = null; + if (error == null) { + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + if (!res.users.isEmpty()) { + user = res.users.get(0); + messagesController.putUser(user, false); + messagesStorage.putUsersAndChats(res.users, null, true, true); + } + } + processFoundUser(user); + })); } } } @@ -479,69 +460,61 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } final String key = dialog_id + "_" + query + "_" + offset + "_" + dialog_id + "_" + user.id + "_" + (user.bot_inline_geo && lastKnownLocation != null && lastKnownLocation.getLatitude() != -1000 ? lastKnownLocation.getLatitude() + lastKnownLocation.getLongitude() : ""); final MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); - RequestDelegate requestDelegate = new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (searchingContextQuery == null || !query.equals(searchingContextQuery)) { - return; - } - contextQueryReqid = 0; - if (cache && response == null) { - searchForContextBotResults(false, user, query, offset); - } else if (delegate != null) { - delegate.onContextSearch(false); - } - if (response != null) { - TLRPC.TL_messages_botResults res = (TLRPC.TL_messages_botResults) response; - if (!cache && res.cache_time != 0) { - messagesStorage.saveBotCache(key, res); - } - nextQueryOffset = res.next_offset; - if (searchResultBotContextSwitch == null) { - searchResultBotContextSwitch = res.switch_pm; - } - for (int a = 0; a < res.results.size(); a++) { - TLRPC.BotInlineResult result = res.results.get(a); - if (!(result.document instanceof TLRPC.TL_document) && !(result.photo instanceof TLRPC.TL_photo) && result.content == null && result.send_message instanceof TLRPC.TL_botInlineMessageMediaAuto) { - res.results.remove(a); - a--; - } - result.query_id = res.query_id; - } - boolean added = false; - if (searchResultBotContext == null || offset.length() == 0) { - searchResultBotContext = res.results; - contextMedia = res.gallery; - } else { - added = true; - searchResultBotContext.addAll(res.results); - if (res.results.isEmpty()) { - nextQueryOffset = ""; - } - } - searchResultHashtags = null; - searchResultUsernames = null; - searchResultUsernamesMap = null; - searchResultCommands = null; - searchResultSuggestions = null; - searchResultCommandsHelp = null; - searchResultCommandsUsers = null; - if (added) { - boolean hasTop = searchResultBotContextSwitch != null; - notifyItemChanged(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0) - 1); - notifyItemRangeInserted(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0), res.results.size()); - } else { - notifyDataSetChanged(); - } - delegate.needChangePanelVisibility(!searchResultBotContext.isEmpty() || searchResultBotContextSwitch != null); - } - } - }); + RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (searchingContextQuery == null || !query.equals(searchingContextQuery)) { + return; } - }; + contextQueryReqid = 0; + if (cache && response == null) { + searchForContextBotResults(false, user, query, offset); + } else if (delegate != null) { + delegate.onContextSearch(false); + } + if (response instanceof TLRPC.TL_messages_botResults) { + TLRPC.TL_messages_botResults res = (TLRPC.TL_messages_botResults) response; + if (!cache && res.cache_time != 0) { + messagesStorage.saveBotCache(key, res); + } + nextQueryOffset = res.next_offset; + if (searchResultBotContextSwitch == null) { + searchResultBotContextSwitch = res.switch_pm; + } + for (int a = 0; a < res.results.size(); a++) { + TLRPC.BotInlineResult result = res.results.get(a); + if (!(result.document instanceof TLRPC.TL_document) && !(result.photo instanceof TLRPC.TL_photo) && result.content == null && result.send_message instanceof TLRPC.TL_botInlineMessageMediaAuto) { + res.results.remove(a); + a--; + } + result.query_id = res.query_id; + } + boolean added = false; + if (searchResultBotContext == null || offset.length() == 0) { + searchResultBotContext = res.results; + contextMedia = res.gallery; + } else { + added = true; + searchResultBotContext.addAll(res.results); + if (res.results.isEmpty()) { + nextQueryOffset = ""; + } + } + searchResultHashtags = null; + searchResultUsernames = null; + searchResultUsernamesMap = null; + searchResultCommands = null; + searchResultSuggestions = null; + searchResultCommandsHelp = null; + searchResultCommandsUsers = null; + if (added) { + boolean hasTop = searchResultBotContextSwitch != null; + notifyItemChanged(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0) - 1); + notifyItemRangeInserted(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0), res.results.size()); + } else { + notifyDataSetChanged(); + } + delegate.needChangePanelVisibility(!searchResultBotContext.isEmpty() || searchResultBotContextSwitch != null); + } + }); if (cache) { messagesStorage.getBotCache(key, requestDelegate); @@ -778,63 +751,52 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { req.filter = new TLRPC.TL_channelParticipantsSearch(); req.filter.q = usernameString; final int currentReqId = ++channelLastReqId; - channelReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (channelReqId != 0 && currentReqId == channelLastReqId && searchResultUsernamesMap != null && searchResultUsernames != null) { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - messagesController.putUsers(res.users, false); - if (!res.participants.isEmpty()) { - int currentUserId = UserConfig.getInstance(currentAccount).getClientUserId(); - for (int a = 0; a < res.participants.size(); a++) { - TLRPC.ChannelParticipant participant = res.participants.get(a); - if (searchResultUsernamesMap.indexOfKey(participant.user_id) >= 0 || !isSearchingMentions && participant.user_id == currentUserId) { - continue; - } - TLRPC.User user = messagesController.getUser(participant.user_id); - if (user == null) { - return; - } - searchResultUsernames.add(user); - } - notifyDataSetChanged(); - } + channelReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (channelReqId != 0 && currentReqId == channelLastReqId && searchResultUsernamesMap != null && searchResultUsernames != null) { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + messagesController.putUsers(res.users, false); + if (!res.participants.isEmpty()) { + int currentUserId = UserConfig.getInstance(currentAccount).getClientUserId(); + for (int a = 0; a < res.participants.size(); a++) { + TLRPC.ChannelParticipant participant = res.participants.get(a); + if (searchResultUsernamesMap.indexOfKey(participant.user_id) >= 0 || !isSearchingMentions && participant.user_id == currentUserId) { + continue; } + TLRPC.User user = messagesController.getUser(participant.user_id); + if (user == null) { + return; + } + searchResultUsernames.add(user); } - channelReqId = 0; + notifyDataSetChanged(); } - }); + } } - }); + channelReqId = 0; + })); } }, 200); } - Collections.sort(searchResultUsernames, new Comparator() { - @Override - public int compare(TLRPC.User lhs, TLRPC.User rhs) { - if (newResultsHashMap.indexOfKey(lhs.id) >= 0 && newResultsHashMap.indexOfKey(rhs.id) >= 0) { - return 0; - } else if (newResultsHashMap.indexOfKey(lhs.id) >= 0) { - return -1; - } else if (newResultsHashMap.indexOfKey(rhs.id) >= 0) { - return 1; - } - int lhsNum = users.indexOf(lhs.id); - int rhsNum = users.indexOf(rhs.id); - if (lhsNum != -1 && rhsNum != -1) { - return lhsNum < rhsNum ? -1 : (lhsNum == rhsNum ? 0 : 1); - } else if (lhsNum != -1 && rhsNum == -1) { - return -1; - } else if (lhsNum == -1 && rhsNum != -1) { - return 1; - } + Collections.sort(searchResultUsernames, (lhs, rhs) -> { + if (newResultsHashMap.indexOfKey(lhs.id) >= 0 && newResultsHashMap.indexOfKey(rhs.id) >= 0) { return 0; + } else if (newResultsHashMap.indexOfKey(lhs.id) >= 0) { + return -1; + } else if (newResultsHashMap.indexOfKey(rhs.id) >= 0) { + return 1; } + int lhsNum = users.indexOf(lhs.id); + int rhsNum = users.indexOf(rhs.id); + if (lhsNum != -1 && rhsNum != -1) { + return lhsNum < rhsNum ? -1 : (lhsNum == rhsNum ? 0 : 1); + } else if (lhsNum != -1 && rhsNum == -1) { + return -1; + } else if (lhsNum == -1 && rhsNum != -1) { + return 1; + } + return 0; }); notifyDataSetChanged(); delegate.needChangePanelVisibility(!newResult.isEmpty()); @@ -893,19 +855,16 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { searchResultSuggestions.add(suggestion); } Emoji.loadRecentEmoji(); - Collections.sort(searchResultSuggestions, new Comparator() { - @Override - public int compare(EmojiSuggestion o1, EmojiSuggestion o2) { - Integer n1 = Emoji.emojiUseHistory.get(o1.emoji); - if (n1 == null) { - n1 = 0; - } - Integer n2 = Emoji.emojiUseHistory.get(o2.emoji); - if (n2 == null) { - n2 = 0; - } - return n2.compareTo(n1); + Collections.sort(searchResultSuggestions, (o1, o2) -> { + Integer n1 = Emoji.emojiUseHistory.get(o1.emoji); + if (n1 == null) { + n1 = 0; } + Integer n2 = Emoji.emojiUseHistory.get(o2.emoji); + if (n2 == null) { + n2 = 0; + } + return n2.compareTo(n1); }); } searchResultHashtags = null; @@ -1057,12 +1016,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { break; case 1: view = new ContextLinkCell(mContext); - ((ContextLinkCell) view).setDelegate(new ContextLinkCell.ContextLinkCellDelegate() { - @Override - public void didPressedImage(ContextLinkCell cell) { - delegate.onContextClick(cell.getResult()); - } - }); + ((ContextLinkCell) view).setDelegate(cell -> delegate.onContextClick(cell.getResult())); break; case 2: view = new BotSwitchCell(mContext); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/PhonebookSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/PhonebookSearchAdapter.java index 7eac0c088..8a5d0e111 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/PhonebookSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/PhonebookSearchAdapter.java @@ -71,113 +71,107 @@ public class PhonebookSearchAdapter extends RecyclerListView.SelectionAdapter { } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - final int currentAccount = UserConfig.selectedAccount; - final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contactsBook.values()); - final ArrayList contactsCopy2 = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(query, new ArrayList<>(), new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + AndroidUtilities.runOnUIThread(() -> { + final int currentAccount = UserConfig.selectedAccount; + final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contactsBook.values()); + final ArrayList contactsCopy2 = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(query, new ArrayList<>(), new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList resultArray = new ArrayList<>(); - ArrayList resultArrayNames = new ArrayList<>(); - SparseBooleanArray foundUids = new SparseBooleanArray(); + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); + SparseBooleanArray foundUids = new SparseBooleanArray(); - for (int a = 0; a < contactsCopy.size(); a++) { - ContactsController.Contact contact = contactsCopy.get(a); - String name = ContactsController.formatName(contact.first_name, contact.last_name).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - String name2; - String tName2; - if (contact.user != null) { - name2 = ContactsController.formatName(contact.user.first_name, contact.user.last_name).toLowerCase(); - tName2 = LocaleController.getInstance().getTranslitString(name); - } else { - name2 = null; - tName2 = null; - } - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name2 != null && (name2.startsWith(q) || name2.contains(" " + q)) || tName2 != null && (tName2.startsWith(q) || tName2.contains(" " + q))) { - found = 1; - } else if (contact.user != null && contact.user.username != null && contact.user.username.startsWith(q)) { - found = 2; - } else if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 3; - } - if (found != 0) { - if (found == 3) { - resultArrayNames.add(AndroidUtilities.generateSearchName(contact.first_name, contact.last_name, q)); - } else if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(contact.user.first_name, contact.user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + contact.user.username, null, "@" + q)); - } - if (contact.user != null) { - foundUids.put(contact.user.id, true); - } - resultArray.add(contact); - break; - } - } - } - - for (int a = 0; a < contactsCopy2.size(); a++) { - TLRPC.TL_contact contact = contactsCopy2.get(a); - if (foundUids.indexOfKey(contact.user_id) >= 0) { - continue; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); - String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (user.username != null && user.username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray.add(user); - break; - } - } - } - - updateSearchResults(query, resultArray, resultArrayNames); + for (int a = 0; a < contactsCopy.size(); a++) { + ContactsController.Contact contact = contactsCopy.get(a); + String name = ContactsController.formatName(contact.first_name, contact.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + String name2; + String tName2; + if (contact.user != null) { + name2 = ContactsController.formatName(contact.user.first_name, contact.user.last_name).toLowerCase(); + tName2 = LocaleController.getInstance().getTranslitString(name); + } else { + name2 = null; + tName2 = null; } - }); - } + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name2 != null && (name2.startsWith(q) || name2.contains(" " + q)) || tName2 != null && (tName2.startsWith(q) || tName2.contains(" " + q))) { + found = 1; + } else if (contact.user != null && contact.user.username != null && contact.user.username.startsWith(q)) { + found = 2; + } else if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 3; + } + if (found != 0) { + if (found == 3) { + resultArrayNames.add(AndroidUtilities.generateSearchName(contact.first_name, contact.last_name, q)); + } else if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(contact.user.first_name, contact.user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + contact.user.username, null, "@" + q)); + } + if (contact.user != null) { + foundUids.put(contact.user.id, true); + } + resultArray.add(contact); + break; + } + } + } + + for (int a = 0; a < contactsCopy2.size(); a++) { + TLRPC.TL_contact contact = contactsCopy2.get(a); + if (foundUids.indexOfKey(contact.user_id) >= 0) { + continue; + } + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(user); + break; + } + } + } + + updateSearchResults(query, resultArray, resultArrayNames); + }); }); } @@ -186,14 +180,11 @@ public class PhonebookSearchAdapter extends RecyclerListView.SelectionAdapter { } private void updateSearchResults(final String query, final ArrayList users, final ArrayList names) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - onUpdateSearchResults(query); - searchResult = users; - searchResultNames = names; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + onUpdateSearchResults(query); + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java index d5f6354d5..452e41095 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java @@ -117,83 +117,74 @@ public class SearchAdapter extends RecyclerListView.SelectionAdapter { } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (allowUsernameSearch) { - searchAdapterHelper.queryServerSearch(query, true, allowChats, allowBots, true, channelId, false); - } - final int currentAccount = UserConfig.selectedAccount; - final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(new ArrayList(), new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } - - ArrayList resultArray = new ArrayList<>(); - ArrayList resultArrayNames = new ArrayList<>(); - - for (int a = 0; a < contactsCopy.size(); a++) { - TLRPC.TL_contact contact = contactsCopy.get(a); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); - if (user.id == UserConfig.getInstance(currentAccount).getClientUserId() || onlyMutual && !user.mutual_contact) { - continue; - } - - String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (user.username != null && user.username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray.add(user); - break; - } - } - } - - updateSearchResults(resultArray, resultArrayNames); - } - }); + AndroidUtilities.runOnUIThread(() -> { + if (allowUsernameSearch) { + searchAdapterHelper.queryServerSearch(query, true, allowChats, allowBots, true, channelId, false); } + final int currentAccount = UserConfig.selectedAccount; + final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>(), new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } + + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); + + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.TL_contact contact = contactsCopy.get(a); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); + if (user.id == UserConfig.getInstance(currentAccount).getClientUserId() || onlyMutual && !user.mutual_contact) { + continue; + } + + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(user); + break; + } + } + } + + updateSearchResults(resultArray, resultArrayNames); + }); }); } private void updateSearchResults(final ArrayList users, final ArrayList names) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchResult = users; - searchResultNames = names; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java index 8331f54e6..282598377 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java @@ -18,13 +18,11 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -116,26 +114,18 @@ public class SearchAdapterHelper { req.offset = 0; req.channel = MessagesController.getInstance(currentAccount).getInputChannel(channelId); final int currentReqId = ++channelLastReqId; - channelReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (currentReqId == channelLastReqId) { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - lastFoundChannel = query.toLowerCase(); - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - groupSearch = res.participants; - delegate.onDataSetChanged(); - } - } - channelReqId = 0; - } - }); + channelReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (currentReqId == channelLastReqId) { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + lastFoundChannel = query.toLowerCase(); + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + groupSearch = res.participants; + delegate.onDataSetChanged(); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + channelReqId = 0; + }), ConnectionsManager.RequestFlagFailOnServerErrors); if (kicked) { req = new TLRPC.TL_channels_getParticipants(); req.filter = new TLRPC.TL_channelParticipantsKicked(); @@ -144,26 +134,18 @@ public class SearchAdapterHelper { req.offset = 0; req.channel = MessagesController.getInstance(currentAccount).getInputChannel(channelId); final int currentReqId2 = ++channelLastReqId2; - channelReqId2 = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (currentReqId2 == channelLastReqId2) { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - lastFoundChannel2 = query.toLowerCase(); - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - groupSearch2 = res.participants; - delegate.onDataSetChanged(); - } - } - channelReqId2 = 0; - } - }); + channelReqId2 = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (currentReqId2 == channelLastReqId2) { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + lastFoundChannel2 = query.toLowerCase(); + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + groupSearch2 = res.participants; + delegate.onDataSetChanged(); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + channelReqId2 = 0; + }), ConnectionsManager.RequestFlagFailOnServerErrors); } } else { groupSearch.clear(); @@ -177,100 +159,92 @@ public class SearchAdapterHelper { req.q = query; req.limit = 50; final int currentReqId = ++lastReqId; - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (currentReqId == lastReqId) { - if (error == null) { - TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; - globalSearch.clear(); - globalSearchMap.clear(); - localServerSearch.clear(); - MessagesController.getInstance(currentAccount).putChats(res.chats, false); - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); - SparseArray chatsMap = new SparseArray<>(); - SparseArray usersMap = new SparseArray<>(); - for (int a = 0; a < res.chats.size(); a++) { - TLRPC.Chat chat = res.chats.get(a); - chatsMap.put(chat.id, chat); + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; + globalSearch.clear(); + globalSearchMap.clear(); + localServerSearch.clear(); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, true); + SparseArray chatsMap = new SparseArray<>(); + SparseArray usersMap = new SparseArray<>(); + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + chatsMap.put(chat.id, chat); + } + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersMap.put(user.id, user); + } + for (int b = 0; b < 2; b++) { + ArrayList arrayList; + if (b == 0) { + if (!allResultsAreGlobal) { + continue; + } + arrayList = res.my_results; + } else { + arrayList = res.results; + } + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Peer peer = arrayList.get(a); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (peer.user_id != 0) { + user = usersMap.get(peer.user_id); + } else if (peer.chat_id != 0) { + chat = chatsMap.get(peer.chat_id); + } else if (peer.channel_id != 0) { + chat = chatsMap.get(peer.channel_id); + } + if (chat != null) { + if (!allowChats) { + continue; } - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersMap.put(user.id, user); + globalSearch.add(chat); + globalSearchMap.put(-chat.id, chat); + } else if (user != null) { + if (!allowBots && user.bot || !allowSelf && user.self) { + continue; } - for (int b = 0; b < 2; b++) { - ArrayList arrayList; - if (b == 0) { - if (!allResultsAreGlobal) { - continue; - } - arrayList = res.my_results; - } else { - arrayList = res.results; - } - for (int a = 0; a < arrayList.size(); a++) { - TLRPC.Peer peer = arrayList.get(a); - TLRPC.User user = null; - TLRPC.Chat chat = null; - if (peer.user_id != 0) { - user = usersMap.get(peer.user_id); - } else if (peer.chat_id != 0) { - chat = chatsMap.get(peer.chat_id); - } else if (peer.channel_id != 0) { - chat = chatsMap.get(peer.channel_id); - } - if (chat != null) { - if (!allowChats) { - continue; - } - globalSearch.add(chat); - globalSearchMap.put(-chat.id, chat); - } else if (user != null) { - if (!allowBots && user.bot || !allowSelf && user.self) { - continue; - } - globalSearch.add(user); - globalSearchMap.put(user.id, user); - } - } - } - if (!allResultsAreGlobal) { - for (int a = 0; a < res.my_results.size(); a++) { - TLRPC.Peer peer = res.my_results.get(a); - TLRPC.User user = null; - TLRPC.Chat chat = null; - if (peer.user_id != 0) { - user = usersMap.get(peer.user_id); - } else if (peer.chat_id != 0) { - chat = chatsMap.get(peer.chat_id); - } else if (peer.channel_id != 0) { - chat = chatsMap.get(peer.channel_id); - } - if (chat != null) { - localServerSearch.add(chat); - globalSearchMap.put(-chat.id, chat); - } else if (user != null) { - localServerSearch.add(user); - globalSearchMap.put(user.id, user); - } - } - } - lastFoundUsername = query.toLowerCase(); - if (localSearchResults != null) { - mergeResults(localSearchResults); - } - delegate.onDataSetChanged(); + globalSearch.add(user); + globalSearchMap.put(user.id, user); } } - reqId = 0; } - }); + if (!allResultsAreGlobal) { + for (int a = 0; a < res.my_results.size(); a++) { + TLRPC.Peer peer = res.my_results.get(a); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (peer.user_id != 0) { + user = usersMap.get(peer.user_id); + } else if (peer.chat_id != 0) { + chat = chatsMap.get(peer.chat_id); + } else if (peer.channel_id != 0) { + chat = chatsMap.get(peer.channel_id); + } + if (chat != null) { + localServerSearch.add(chat); + globalSearchMap.put(-chat.id, chat); + } else if (user != null) { + localServerSearch.add(user); + globalSearchMap.put(user.id, user); + } + } + } + lastFoundUsername = query.toLowerCase(); + if (localSearchResults != null) { + mergeResults(localSearchResults); + } + delegate.onDataSetChanged(); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + reqId = 0; + }), ConnectionsManager.RequestFlagFailOnServerErrors); } else { globalSearch.clear(); globalSearchMap.clear(); @@ -289,42 +263,31 @@ public class SearchAdapterHelper { if (hashtagsLoadedFromDb) { return true; } - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT id, date FROM hashtag_recent_v2 WHERE 1"); - final ArrayList arrayList = new ArrayList<>(); - final HashMap hashMap = new HashMap<>(); - while (cursor.next()) { - HashtagObject hashtagObject = new HashtagObject(); - hashtagObject.hashtag = cursor.stringValue(0); - hashtagObject.date = cursor.intValue(1); - arrayList.add(hashtagObject); - hashMap.put(hashtagObject.hashtag, hashtagObject); - } - cursor.dispose(); - Collections.sort(arrayList, new Comparator() { - @Override - public int compare(HashtagObject lhs, HashtagObject rhs) { - if (lhs.date < rhs.date) { - return 1; - } else if (lhs.date > rhs.date) { - return -1; - } else { - return 0; - } - } - }); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - setHashtags(arrayList, hashMap); - } - }); - } catch (Exception e) { - FileLog.e(e); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + SQLiteCursor cursor = MessagesStorage.getInstance(currentAccount).getDatabase().queryFinalized("SELECT id, date FROM hashtag_recent_v2 WHERE 1"); + final ArrayList arrayList = new ArrayList<>(); + final HashMap hashMap = new HashMap<>(); + while (cursor.next()) { + HashtagObject hashtagObject = new HashtagObject(); + hashtagObject.hashtag = cursor.stringValue(0); + hashtagObject.date = cursor.intValue(1); + arrayList.add(hashtagObject); + hashMap.put(hashtagObject.hashtag, hashtagObject); } + cursor.dispose(); + Collections.sort(arrayList, (lhs, rhs) -> { + if (lhs.date < rhs.date) { + return 1; + } else if (lhs.date > rhs.date) { + return -1; + } else { + return 0; + } + }); + AndroidUtilities.runOnUIThread(() -> setHashtags(arrayList, hashMap)); + } catch (Exception e) { + FileLog.e(e); } }); return false; @@ -367,7 +330,7 @@ public class SearchAdapterHelper { return; } boolean changed = false; - Pattern pattern = Pattern.compile("(^|\\s)#[\\w@\\.]+"); + Pattern pattern = Pattern.compile("(^|\\s)#[\\w@.]+"); Matcher matcher = pattern.matcher(message); while (matcher.find()) { int start = matcher.start(); @@ -398,34 +361,31 @@ public class SearchAdapterHelper { } private void putRecentHashtags(final ArrayList arrayList) { - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - MessagesStorage.getInstance(currentAccount).getDatabase().beginTransaction(); - SQLitePreparedStatement state = MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("REPLACE INTO hashtag_recent_v2 VALUES(?, ?)"); - for (int a = 0; a < arrayList.size(); a++) { - if (a == 100) { - break; - } - HashtagObject hashtagObject = arrayList.get(a); - state.requery(); - state.bindString(1, hashtagObject.hashtag); - state.bindInteger(2, hashtagObject.date); - state.step(); + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + MessagesStorage.getInstance(currentAccount).getDatabase().beginTransaction(); + SQLitePreparedStatement state = MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("REPLACE INTO hashtag_recent_v2 VALUES(?, ?)"); + for (int a = 0; a < arrayList.size(); a++) { + if (a == 100) { + break; } - state.dispose(); - MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); - if (arrayList.size() >= 100) { - MessagesStorage.getInstance(currentAccount).getDatabase().beginTransaction(); - for (int a = 100; a < arrayList.size(); a++) { - MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE id = '" + arrayList.get(a).hashtag + "'").stepThis().dispose(); - } - MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); - } - } catch (Exception e) { - FileLog.e(e); + HashtagObject hashtagObject = arrayList.get(a); + state.requery(); + state.bindString(1, hashtagObject.hashtag); + state.bindInteger(2, hashtagObject.date); + state.step(); } + state.dispose(); + MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); + if (arrayList.size() >= 100) { + MessagesStorage.getInstance(currentAccount).getDatabase().beginTransaction(); + for (int a = 100; a < arrayList.size(); a++) { + MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE id = '" + arrayList.get(a).hashtag + "'").stepThis().dispose(); + } + MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); + } + } catch (Exception e) { + FileLog.e(e); } }); } @@ -465,14 +425,11 @@ public class SearchAdapterHelper { public void clearRecentHashtags() { hashtags = new ArrayList<>(); hashtagsByText = new HashMap<>(); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE 1").stepThis().dispose(); - } catch (Exception e) { - FileLog.e(e); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE 1").stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java index 986504087..01ef295d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersAdapter.java @@ -21,8 +21,6 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.messenger.FileLoader; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Cells.StickerCell; import org.telegram.ui.Components.RecyclerListView; @@ -264,33 +262,25 @@ public class StickersAdapter extends RecyclerListView.SelectionAdapter implement TLRPC.TL_messages_getStickers req = new TLRPC.TL_messages_getStickers(); req.emoticon = emoji; req.hash = 0; - lastReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - lastReqId = 0; - if (!emoji.equals(lastSticker) || !(response instanceof TLRPC.TL_messages_stickers)) { - return; - } - delayLocalResults = false; - TLRPC.TL_messages_stickers res = (TLRPC.TL_messages_stickers) response; - int oldCount = stickers != null ? stickers.size() : 0; - addStickersToResult(res.stickers); - int newCount = stickers != null ? stickers.size() : 0; - if (!visible && stickers != null && !stickers.isEmpty()) { - checkStickerFilesExistAndDownload(); - delegate.needChangePanelVisibility(stickers != null && !stickers.isEmpty() && stickersToLoad.isEmpty()); - visible = true; - } - if (oldCount != newCount) { - notifyDataSetChanged(); - } - } - }); + lastReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + lastReqId = 0; + if (!emoji.equals(lastSticker) || !(response instanceof TLRPC.TL_messages_stickers)) { + return; } - }); + delayLocalResults = false; + TLRPC.TL_messages_stickers res = (TLRPC.TL_messages_stickers) response; + int oldCount = stickers != null ? stickers.size() : 0; + addStickersToResult(res.stickers); + int newCount = stickers != null ? stickers.size() : 0; + if (!visible && stickers != null && !stickers.isEmpty()) { + checkStickerFilesExistAndDownload(); + delegate.needChangePanelVisibility(stickers != null && !stickers.isEmpty() && stickersToLoad.isEmpty()); + visible = true; + } + if (oldCount != newCount) { + notifyDataSetChanged(); + } + })); } public void clearStickers() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index cc90b1cb8..029a6471d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -79,6 +79,10 @@ import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildConfig; @@ -97,9 +101,6 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.browser.Browser; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.messenger.support.widget.GridLayoutManager; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; @@ -135,6 +136,7 @@ import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.Components.WebPlayerView; import java.io.File; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; @@ -1606,11 +1608,15 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (url != null) { int index; boolean isAnchor = false; - final String anchor; + String anchor; if ((index = url.lastIndexOf('#')) != -1) { - anchor = url.substring(index + 1); + try { + anchor = URLDecoder.decode(url.substring(index + 1), "UTF-8"); + } catch (Exception ignore) { + anchor = ""; + } if (url.toLowerCase().contains(currentPage.url.toLowerCase())) { - Integer row = anchors.get(anchor); + Integer row = anchors.get(anchor.toLowerCase()); if (row != null) { layoutManager.scrollToPositionWithOffset(row, 0); isAnchor = true; @@ -1621,6 +1627,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } if (!isAnchor) { if (openUrlReqId == 0) { + final String anchorFinal = anchor; showProgressView(true); final TLRPC.TL_messages_getWebPage req = new TLRPC.TL_messages_getWebPage(); req.url = pressedLink.getUrl(); @@ -1638,7 +1645,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg showProgressView(false); if (isVisible) { if (response instanceof TLRPC.TL_webPage && ((TLRPC.TL_webPage) response).cached_page instanceof TLRPC.TL_pageFull) { - addPageToStack((TLRPC.TL_webPage) response, anchor); + addPageToStack((TLRPC.TL_webPage) response, anchorFinal); } else { Browser.openUrl(parentActivity, req.url); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java index 7151dac18..d133e333c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; @@ -101,40 +100,31 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (position >= MessagesController.getInstance(currentAccount).blockedUsers.size()) { - return; - } - Bundle args = new Bundle(); - args.putInt("user_id", MessagesController.getInstance(currentAccount).blockedUsers.get(position)); - presentFragment(new ProfileActivity(args)); + listView.setOnItemClickListener((view, position) -> { + if (position >= MessagesController.getInstance(currentAccount).blockedUsers.size()) { + return; } + Bundle args = new Bundle(); + args.putInt("user_id", MessagesController.getInstance(currentAccount).blockedUsers.get(position)); + presentFragment(new ProfileActivity(args)); }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (position >= MessagesController.getInstance(currentAccount).blockedUsers.size() || getParentActivity() == null) { - return true; - } - selectedUserId = MessagesController.getInstance(currentAccount).blockedUsers.get(position); - - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - CharSequence[] items = new CharSequence[]{LocaleController.getString("Unblock", R.string.Unblock)}; - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - MessagesController.getInstance(currentAccount).unblockUser(selectedUserId); - } - } - }); - showDialog(builder.create()); - + listView.setOnItemLongClickListener((view, position) -> { + if (position >= MessagesController.getInstance(currentAccount).blockedUsers.size() || getParentActivity() == null) { return true; } + selectedUserId = MessagesController.getInstance(currentAccount).blockedUsers.get(position); + + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + CharSequence[] items = new CharSequence[]{LocaleController.getString("Unblock", R.string.Unblock)}; + builder.setItems(items, (dialogInterface, i) -> { + if (i == 0) { + MessagesController.getInstance(currentAccount).unblockUser(selectedUserId); + } + }); + showDialog(builder.create()); + + return true; }); if (MessagesController.getInstance(currentAccount).loadingBlockedUsers) { @@ -199,7 +189,7 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe @Override public int getItemCount() { - if (MessagesController.getInstance(currentAccount).blockedUsers.isEmpty()) { + if (MessagesController.getInstance(currentAccount).blockedUsers.size() == 0) { return 0; } return MessagesController.getInstance(currentAccount).blockedUsers.size() + 1; @@ -255,16 +245,13 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof UserCell) { - ((UserCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof UserCell) { + ((UserCell) child).update(0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java index 07683ec69..fb7883762 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ArchivedStickerSetCell.java @@ -15,7 +15,6 @@ import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; -import android.view.View; import android.widget.CompoundButton; import android.widget.FrameLayout; import android.widget.TextView; @@ -108,11 +107,8 @@ public class ArchivedStickerSetCell extends FrameLayout { public void setOnCheckClick(CompoundButton.OnCheckedChangeListener listener) { checkBox.setOnCheckedChangeListener(onCheckedChangeListener = listener); - checkBox.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { + checkBox.setOnClickListener(v -> { - } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java index 116238805..0cc8c64ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java @@ -16,7 +16,6 @@ import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; -import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -58,21 +57,18 @@ public class AudioCell extends FrameLayout { playButton = new ImageView(context); addView(playButton, LayoutHelper.createFrame(46, 46, ((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP), LocaleController.isRTL ? 0 : 13, 13, LocaleController.isRTL ? 13 : 0, 0)); - playButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (audioEntry != null) { - if (MediaController.getInstance().isPlayingMessage(audioEntry.messageObject) && !MediaController.getInstance().isMessagePaused()) { - MediaController.getInstance().pauseMessage(audioEntry.messageObject); - setPlayDrawable(false); - } else { - ArrayList arrayList = new ArrayList<>(); - arrayList.add(audioEntry.messageObject); - if (MediaController.getInstance().setPlaylist(arrayList, audioEntry.messageObject)) { - setPlayDrawable(true); - if (delegate != null) { - delegate.startedPlayingAudio(audioEntry.messageObject); - } + playButton.setOnClickListener(v -> { + if (audioEntry != null) { + if (MediaController.getInstance().isPlayingMessage(audioEntry.messageObject) && !MediaController.getInstance().isMessagePaused()) { + MediaController.getInstance().pauseMessage(audioEntry.messageObject); + setPlayDrawable(false); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(audioEntry.messageObject); + if (MediaController.getInstance().setPlaylist(arrayList, audioEntry.messageObject)) { + setPlayDrawable(true); + if (delegate != null) { + delegate.startedPlayingAudio(audioEntry.messageObject); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BrightnessControlCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BrightnessControlCell.java index b56ab6178..c24699561 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BrightnessControlCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BrightnessControlCell.java @@ -45,12 +45,7 @@ public class BrightnessControlCell extends FrameLayout { } }; seekBarView.setReportChanges(true); - seekBarView.setDelegate(new SeekBarView.SeekBarViewDelegate() { - @Override - public void onSeekBarDrag(float progress) { - didChangedValue(progress); - } - }); + seekBarView.setDelegate(this::didChangedValue); addView(seekBarView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.TOP | Gravity.LEFT, 58, 9, 58, 0)); rightImageView = new ImageView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 4021e9a6f..3171c4b97 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -522,7 +522,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (end >= block.charactersEnd) { for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, isMono ? URLSpanMono.class : ClickableSpan.class); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); + } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { break; } @@ -538,7 +543,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int offsetY = 0; for (int a = blockNum - 1; a >= 0; a--) { MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); - CharacterStyle[] nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, isMono ? URLSpanMono.class : ClickableSpan.class); + CharacterStyle[] nextLink; + if (isMono) { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, URLSpanMono.class); + } else { + nextLink = buffer.getSpans(nextBlock.charactersEnd - 1, nextBlock.charactersEnd - 1, ClickableSpan.class); + } if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { break; } @@ -1215,6 +1225,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!disallowLongPress && result && event.getAction() == MotionEvent.ACTION_DOWN) { startCheckLongPress(); } + if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { cancelCheckLongPress(); } @@ -1624,9 +1635,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lat = (Math.PI / 2.0 - 2 * Math.atan(Math.exp((y - offset) / rad))) * 180.0 / Math.PI; url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), false, 15); } else if (!TextUtils.isEmpty(object.messageOwner.media.title)) { - url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, 72, 72, true, 15); + int photoWidth = backgroundWidth - AndroidUtilities.dp(21); + int photoHeight = AndroidUtilities.dp(195); + url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15); } else { - url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, 200, 100, true, 15); + int photoWidth = backgroundWidth - AndroidUtilities.dp(12); + int photoHeight = AndroidUtilities.dp(195); + url = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15); } return !url.equals(currentUrl); } else if (currentPhotoObject == null || currentPhotoObject.location instanceof TLRPC.TL_fileLocationUnavailable) { @@ -3203,12 +3218,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate infoLayout = null; } } else { - availableTimeWidth = AndroidUtilities.dp(200 - 14); - photoWidth = AndroidUtilities.dp(200); - photoHeight = AndroidUtilities.dp(100); - backgroundWidth = photoWidth + AndroidUtilities.dp(12); - currentUrl = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, 200, 100, true, 15); - currentWebFile = WebFile.createWithGeoPoint(point, 200, 100, 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.needDrawAvatar() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(252 + 37)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.needDrawAvatar() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(252 + 37)); + } + if (checkNeedDrawShareButton(messageObject)) { + backgroundWidth -= AndroidUtilities.dp(20); + } + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(34); + + photoWidth = backgroundWidth - AndroidUtilities.dp(12); + photoHeight = AndroidUtilities.dp(195); + + currentUrl = AndroidUtilities.formapMapUrl(currentAccount, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), true, 15); + currentWebFile = WebFile.createWithGeoPoint(point, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); } if ((int) messageObject.getDialogId() == 0) { if (SharedConfig.mapPreviewType == 0) { @@ -3263,13 +3287,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoWidth *= maxHeight / photoHeight; photoHeight = (int) maxHeight; } - availableTimeWidth = AndroidUtilities.dp(1000); - measureTime(messageObject); - if (photoWidth - AndroidUtilities.dp(14) < timeWidth) { - photoWidth = timeWidth + AndroidUtilities.dp(14); - } documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; - availableTimeWidth = photoWidth - AndroidUtilities.dp(14); + availableTimeWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(14); backgroundWidth = photoWidth + AndroidUtilities.dp(12); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); @@ -4619,15 +4638,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOutOwner()) { Theme.chat_audioTitlePaint.setColor(Theme.getColor(Theme.key_chat_outAudioTitleText)); - Theme.chat_audioPerformerPaint.setColor(Theme.getColor(Theme.key_chat_outAudioPerfomerText)); - Theme.chat_audioTimePaint.setColor(Theme.getColor(Theme.key_chat_outAudioDurationText)); + Theme.chat_audioPerformerPaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_outAudioPerfomerSelectedText : Theme.key_chat_outAudioPerfomerText)); + Theme.chat_audioTimePaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_outAudioDurationSelectedText : Theme.key_chat_outAudioDurationText)); radialProgress.setProgressColor(Theme.getColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.key_chat_outAudioSelectedProgress : Theme.key_chat_outAudioProgress)); } else { Theme.chat_audioTitlePaint.setColor(Theme.getColor(Theme.key_chat_inAudioTitleText)); - Theme.chat_audioPerformerPaint.setColor(Theme.getColor(Theme.key_chat_inAudioPerfomerText)); - Theme.chat_audioTimePaint.setColor(Theme.getColor(Theme.key_chat_inAudioDurationText)); + Theme.chat_audioPerformerPaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_inAudioPerfomerSelectedText : Theme.key_chat_inAudioPerfomerText)); + Theme.chat_audioTimePaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_inAudioDurationSelectedText : Theme.key_chat_inAudioDurationText)); radialProgress.setProgressColor(Theme.getColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } + radialProgress.draw(canvas); canvas.save(); @@ -4832,8 +4852,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate setDrawableBounds(phone, x + AndroidUtilities.dp(205), otherY = AndroidUtilities.dp(22)); phone.draw(canvas); } else if (currentMessageObject.type == 12) { - Theme.chat_contactNamePaint.setColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outContactNameText : Theme.key_chat_inContactNameText)); - Theme.chat_contactPhonePaint.setColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outContactPhoneText : Theme.key_chat_inContactPhoneText)); + if (currentMessageObject.isOutOwner()) { + Theme.chat_contactNamePaint.setColor(Theme.getColor(Theme.key_chat_outContactNameText)); + Theme.chat_contactPhonePaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_outContactPhoneSelectedText : Theme.key_chat_outContactPhoneText)); + } else { + Theme.chat_contactNamePaint.setColor(Theme.getColor(Theme.key_chat_inContactNameText)); + Theme.chat_contactPhonePaint.setColor(Theme.getColor(isDrawSelectedBackground() ? Theme.key_chat_inContactPhoneSelectedText : Theme.key_chat_inContactPhoneText)); + } if (titleLayout != null) { canvas.save(); canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(16) + namesOffset); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java index 35e73bc43..a177dd8e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java @@ -91,12 +91,7 @@ public class ManageChatUserCell extends FrameLayout { optionsButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_stickers_menu), PorterDuff.Mode.MULTIPLY)); optionsButton.setScaleType(ImageView.ScaleType.CENTER); addView(optionsButton, LayoutHelper.createFrame(48, 64, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP)); - optionsButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - delegate.onOptionsButtonCheck(ManageChatUserCell.this, true); - } - }); + optionsButton.setOnClickListener(v -> delegate.onOptionsButtonCheck(ManageChatUserCell.this, true)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index cf2e314e3..b9bf46f58 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -71,7 +71,7 @@ public class TextCell extends FrameLayout { int height = AndroidUtilities.dp(48); valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(24), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 24), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 24) - valueTextView.getTextWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); valueImageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 462a9be3b..7ba4f90d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -121,8 +121,8 @@ public class UserCell extends FrameLayout { } } - public void setData(TLObject user, CharSequence name, CharSequence status, int resId) { - if (user == null && name == null && status == null) { + public void setData(TLObject object, CharSequence name, CharSequence status, int resId) { + if (object == null && name == null && status == null) { currrntStatus = null; currentName = null; currentObject = null; @@ -133,7 +133,7 @@ public class UserCell extends FrameLayout { } currrntStatus = status; currentName = name; - currentObject = user; + currentObject = object; currentDrawable = resId; update(0); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index f49a4ea67..7ac49df74 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -52,6 +52,8 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildConfig; import org.telegram.messenger.BuildVars; @@ -71,7 +73,6 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.LinearSmoothScrollerMiddle; import org.telegram.messenger.support.widget.RecyclerView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java index cdf323b18..a7b700407 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableStringBuilder; @@ -35,7 +34,6 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -105,12 +103,9 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen currentChat = MessagesController.getInstance(currentAccount).getChat(chat_id); if (currentChat == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentChat = MessagesStorage.getInstance(currentAccount).getChat(chat_id); - countDownLatch.countDown(); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + currentChat = MessagesStorage.getInstance(currentAccount).getChat(chat_id); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -229,70 +224,64 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); listView.setAdapter(listViewAdapter); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, final int position) { - if (getParentActivity() == null) { - return; - } - if (listView.getAdapter() == searchListViewAdapter) { - Bundle args = new Bundle(); - args.putInt("user_id", searchListViewAdapter.getItem(position).user_id); - presentFragment(new ProfileActivity(args)); - } else { - if (position >= membersStartRow && position < membersEndRow) { - int user_id; - if (!sortedUsers.isEmpty()) { - user_id = info.participants.participants.get(sortedUsers.get(position - membersStartRow)).user_id; - } else { - user_id = info.participants.participants.get(position - membersStartRow).user_id; - } - Bundle args = new Bundle(); - args.putInt("user_id", user_id); - presentFragment(new ProfileActivity(args)); - } else if (position == blockedUsersRow || position == managementRow) { - Bundle args = new Bundle(); - args.putInt("chat_id", chat_id); - if (position == blockedUsersRow) { - args.putInt("type", 0); - } else if (position == managementRow) { - args.putInt("type", 1); - } - presentFragment(new ChannelUsersActivity(args)); - } else if (position == permissionsRow) { - ChannelPermissionsActivity permissions = new ChannelPermissionsActivity(chat_id); - permissions.setInfo(info); - presentFragment(permissions); - } else if (position == eventLogRow) { - presentFragment(new ChannelAdminLogActivity(currentChat)); - } else if (position == infoRow) { - Bundle args = new Bundle(); - args.putInt("chat_id", chat_id); - ChannelEditInfoActivity fragment = new ChannelEditInfoActivity(args); - fragment.setInfo(info); - presentFragment(fragment); + listView.setOnItemClickListener((view, position) -> { + if (getParentActivity() == null) { + return; + } + if (listView.getAdapter() == searchListViewAdapter) { + Bundle args = new Bundle(); + args.putInt("user_id", searchListViewAdapter.getItem(position).user_id); + presentFragment(new ProfileActivity(args)); + } else { + if (position >= membersStartRow && position < membersEndRow) { + int user_id; + if (!sortedUsers.isEmpty()) { + user_id = info.participants.participants.get(sortedUsers.get(position - membersStartRow)).user_id; + } else { + user_id = info.participants.participants.get(position - membersStartRow).user_id; } + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ProfileActivity(args)); + } else if (position == blockedUsersRow || position == managementRow) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat_id); + if (position == blockedUsersRow) { + args.putInt("type", 0); + } else if (position == managementRow) { + args.putInt("type", 1); + } + presentFragment(new ChannelUsersActivity(args)); + } else if (position == permissionsRow) { + ChannelPermissionsActivity permissions = new ChannelPermissionsActivity(chat_id); + permissions.setInfo(info); + presentFragment(permissions); + } else if (position == eventLogRow) { + presentFragment(new ChannelAdminLogActivity(currentChat)); + } else if (position == infoRow) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat_id); + ChannelEditInfoActivity fragment = new ChannelEditInfoActivity(args); + fragment.setInfo(info); + presentFragment(fragment); } } }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (position >= membersStartRow && position < membersEndRow) { - if (getParentActivity() == null) { - return false; - } - final TLRPC.TL_chatChannelParticipant user; - if (!sortedUsers.isEmpty()) { - user = (TLRPC.TL_chatChannelParticipant) info.participants.participants.get(sortedUsers.get(position - membersStartRow)); - } else { - user = (TLRPC.TL_chatChannelParticipant) info.participants.participants.get(position - membersStartRow); - } - return createMenuForParticipant(user, null, false); + listView.setOnItemLongClickListener((view, position) -> { + if (position >= membersStartRow && position < membersEndRow) { + if (getParentActivity() == null) { + return false; } - return false; + final TLRPC.TL_chatChannelParticipant user; + if (!sortedUsers.isEmpty()) { + user = (TLRPC.TL_chatChannelParticipant) info.participants.participants.get(sortedUsers.get(position - membersStartRow)); + } else { + user = (TLRPC.TL_chatChannelParticipant) info.participants.participants.get(position - membersStartRow); + } + return createMenuForParticipant(user, null, false); } + return false; }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -359,42 +348,34 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen req.filter = new TLRPC.TL_channelParticipantsRecent(); req.offset = reload ? 0 : participantsMap.size(); req.limit = 200; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - if (res.users.size() < 200) { - usersEndReached = true; - } - if (req.offset == 0) { - participantsMap.clear(); - info.participants = new TLRPC.TL_chatParticipants(); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); - MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); - } - for (int a = 0; a < res.participants.size(); a++) { - TLRPC.TL_chatChannelParticipant participant = new TLRPC.TL_chatChannelParticipant(); - participant.channelParticipant = res.participants.get(a); - participant.inviter_id = participant.channelParticipant.inviter_id; - participant.user_id = participant.channelParticipant.user_id; - participant.date = participant.channelParticipant.date; - if (participantsMap.indexOfKey(participant.user_id) < 0) { - info.participants.participants.add(participant); - participantsMap.put(participant.user_id, participant); - } - } - } - loadingUsers = false; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, true, null); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + if (res.users.size() < 200) { + usersEndReached = true; + } + if (req.offset == 0) { + participantsMap.clear(); + info.participants = new TLRPC.TL_chatParticipants(); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); + } + for (int a = 0; a < res.participants.size(); a++) { + TLRPC.TL_chatChannelParticipant participant = new TLRPC.TL_chatChannelParticipant(); + participant.channelParticipant = res.participants.get(a); + participant.inviter_id = participant.channelParticipant.inviter_id; + participant.user_id = participant.channelParticipant.user_id; + participant.date = participant.channelParticipant.date; + if (participantsMap.indexOfKey(participant.user_id) < 0) { + info.participants.participants.add(participant); + participantsMap.put(participant.user_id, participant); } - }, delay); + } } - }); + loadingUsers = false; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, true, null); + }, delay)); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -509,64 +490,58 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen final TLRPC.ChannelParticipant channelParticipantFinal = channelParticipant; final TLRPC.TL_chatChannelParticipant userFinal = user; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(items.toArray(new CharSequence[items.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, final int i) { - if (actions.get(i) == 2) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chat_id, MessagesController.getInstance(currentAccount).getUser(uid), info); - } else { - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(channelParticipantFinal.user_id, chat_id, channelParticipantFinal.admin_rights, channelParticipantFinal.banned_rights, actions.get(i), true); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - channelParticipantFinal.admin_rights = rightsAdmin; - channelParticipantFinal.banned_rights = rightsBanned; - if (actions.get(i) == 0) { - if (userFinal != null) { - if (rights == 1) { - userFinal.channelParticipant = new TLRPC.TL_channelParticipantAdmin(); - } else { - userFinal.channelParticipant = new TLRPC.TL_channelParticipant(); + builder.setItems(items.toArray(new CharSequence[items.size()]), (dialogInterface, i) -> { + if (actions.get(i) == 2) { + MessagesController.getInstance(currentAccount).deleteUserFromChat(chat_id, MessagesController.getInstance(currentAccount).getUser(uid), info); + } else { + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(channelParticipantFinal.user_id, chat_id, channelParticipantFinal.admin_rights, channelParticipantFinal.banned_rights, actions.get(i), true); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> { + channelParticipantFinal.admin_rights = rightsAdmin; + channelParticipantFinal.banned_rights = rightsBanned; + if (actions.get(i) == 0) { + if (userFinal != null) { + if (rights == 1) { + userFinal.channelParticipant = new TLRPC.TL_channelParticipantAdmin(); + } else { + userFinal.channelParticipant = new TLRPC.TL_channelParticipant(); + } + userFinal.channelParticipant.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); + userFinal.channelParticipant.user_id = userFinal.user_id; + userFinal.channelParticipant.date = userFinal.date; + } + } else if (actions.get(i) == 1) { + if (rights == 0) { + if (currentChat.megagroup && info != null && info.participants != null) { + boolean changed = false; + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) info.participants.participants.get(a)).channelParticipant; + if (p.user_id == uid) { + if (info != null) { + info.participants_count--; + } + info.participants.participants.remove(a); + changed = true; + break; } - userFinal.channelParticipant.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); - userFinal.channelParticipant.user_id = userFinal.user_id; - userFinal.channelParticipant.date = userFinal.date; } - } else if (actions.get(i) == 1) { - if (rights == 0) { - if (currentChat.megagroup && info != null && info.participants != null) { - boolean changed = false; - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) info.participants.participants.get(a)).channelParticipant; - if (p.user_id == uid) { - if (info != null) { - info.participants_count--; - } - info.participants.participants.remove(a); - changed = true; - break; - } - } - if (info != null && info.participants != null) { - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant p = info.participants.participants.get(a); - if (p.user_id == uid) { - info.participants.participants.remove(a); - changed = true; - break; - } - } - } - if (changed) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, true, null); + if (info != null && info.participants != null) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant p = info.participants.participants.get(a); + if (p.user_id == uid) { + info.participants.participants.remove(a); + changed = true; + break; } } } + if (changed) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, true, null); + } } } - }); - presentFragment(fragment); - } + } + }); + presentFragment(fragment); } }); showDialog(builder.create()); @@ -624,12 +599,7 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchAdapterHelper.queryServerSearch(query, false, false, true, true, chat_id, false); - } - }); + AndroidUtilities.runOnUIThread(() -> searchAdapterHelper.queryServerSearch(query, false, false, true, true, chat_id, false)); } @Override @@ -650,12 +620,7 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = new ManageChatUserCell(mContext, 8, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - return createMenuForParticipant(null, getItem((Integer) cell.getTag()), !click); - } - }); + ((ManageChatUserCell) view).setDelegate((cell, click) -> createMenuForParticipant(null, getItem((Integer) cell.getTag()), !click)); return new RecyclerListView.Holder(view); } @@ -726,18 +691,15 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen case 1: view = new ManageChatUserCell(mContext, 8, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - int i = (Integer) cell.getTag(); - TLRPC.ChatParticipant part; - if (!sortedUsers.isEmpty()) { - part = info.participants.participants.get(sortedUsers.get(i - membersStartRow)); - } else { - part = info.participants.participants.get(i - membersStartRow); - } - return createMenuForParticipant((TLRPC.TL_chatChannelParticipant) part, null, !click); + ((ManageChatUserCell) view).setDelegate((cell, click) -> { + int i = (Integer) cell.getTag(); + TLRPC.ChatParticipant part; + if (!sortedUsers.isEmpty()) { + part = info.participants.participants.get(sortedUsers.get(i - membersStartRow)); + } else { + part = info.participants.participants.get(i - membersStartRow); } + return createMenuForParticipant((TLRPC.TL_chatChannelParticipant) part, null, !click); }); break; case 2: @@ -836,22 +798,20 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof ManageChatUserCell) { - ((ManageChatUserCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof ManageChatUserCell) { + ((ManageChatUserCell) child).update(0); } } } }; return new ThemeDescription[]{ - new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{ManageChatTextCell.class, ManageChatUserCell.class}, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray), new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUBACKGROUND, null, null, null, null, Theme.key_actionBarDefaultSubmenuBackground), new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM, null, null, null, null, Theme.key_actionBarDefaultSubmenuItem), @@ -863,14 +823,16 @@ public class ChannelEditActivity extends BaseFragment implements NotificationCen new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider), new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow), - new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), - new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGreenText2), - new ThemeDescription(listView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteRedText5), + new ThemeDescription(listView, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), + new ThemeDescription(listView, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGreenText2), + new ThemeDescription(listView, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteRedText5), + new ThemeDescription(listView, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{ManageChatTextCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteValueText), new ThemeDescription(listView, 0, new Class[]{ManageChatTextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon), new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText), new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteGrayText), new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusOnlineColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteBlueText), + new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"optionsButton"}, null, null, null, Theme.key_stickers_menu), new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, null, new Drawable[]{Theme.avatar_photoDrawable, Theme.avatar_broadcastDrawable, Theme.avatar_savedDrawable}, null, Theme.key_avatar_text), new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed), new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundOrange), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditInfoActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditInfoActivity.java index 6e7b6ee66..43036d1a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditInfoActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditInfoActivity.java @@ -20,7 +20,6 @@ import android.text.InputType; import android.text.TextWatcher; import android.util.TypedValue; import android.view.Gravity; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; @@ -42,8 +41,6 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; @@ -156,12 +153,9 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate currentChat = MessagesController.getInstance(currentAccount).getChat(chatId); if (currentChat == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentChat = MessagesStorage.getInstance(currentAccount).getChat(chatId); - countDownLatch.countDown(); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + currentChat = MessagesStorage.getInstance(currentAccount).getChat(chatId); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -190,20 +184,12 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); req.username = "1"; req.channel = new TLRPC.TL_inputChannelEmpty(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - canCreatePublic = error == null || !error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH"); - if (!canCreatePublic) { - loadAdminedChannels(); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + canCreatePublic = error == null || !error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH"); + if (!canCreatePublic) { + loadAdminedChannels(); } - }); + })); } imageUpdater.parentFragment = this; imageUpdater.delegate = this; @@ -277,17 +263,14 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - createAfterUpload = false; - progressDialog = null; - donePressed = false; - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + createAfterUpload = false; + progressDialog = null; + donePressed = false; + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); progressDialog.show(); @@ -306,7 +289,7 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate if (info != null && !info.about.equals(descriptionTextView.getText().toString())) { MessagesController.getInstance(currentAccount).updateChannelAbout(chatId, descriptionTextView.getText().toString(), info); } - if (headerCell2 != null && headerCell2.getVisibility() == View.VISIBLE && info != null && currentChat.creator && info.hidden_prehistory != historyHidden) { + if (headerCell2 != null && headerCell2.getVisibility() == View.VISIBLE && info != null && (currentChat.creator || currentChat.admin_rights != null && currentChat.admin_rights.change_info) && info.hidden_prehistory != historyHidden) { info.hidden_prehistory = historyHidden; MessagesController.getInstance(currentAccount).toogleChannelInvitesHistory(chatId, historyHidden); } @@ -351,38 +334,32 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate avatarDrawable.setInfo(5, null, null, false); avatarDrawable.setDrawPhoto(true); frameLayout.addView(avatarImage, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 16, 12, LocaleController.isRTL ? 16 : 0, 12)); - avatarImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - - CharSequence[] items; - - if (avatar != null) { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; - } else { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; - } - - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - imageUpdater.openCamera(); - } else if (i == 1) { - imageUpdater.openGallery(); - } else if (i == 2) { - avatar = null; - uploadedAvatar = null; - avatarImage.setImage(avatar, "50_50", avatarDrawable); - } - } - }); - showDialog(builder.create()); + avatarImage.setOnClickListener(view -> { + if (getParentActivity() == null) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + + CharSequence[] items; + + if (avatar != null) { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; + } else { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; + } + + builder.setItems(items, (dialogInterface, i) -> { + if (i == 0) { + imageUpdater.openCamera(); + } else if (i == 1) { + imageUpdater.openGallery(); + } else if (i == 2) { + avatar = null; + uploadedAvatar = null; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + } + }); + showDialog(builder.create()); }); nameTextView = new EditTextBoldCursor(context); @@ -455,15 +432,12 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate descriptionTextView.setCursorSize(AndroidUtilities.dp(20)); descriptionTextView.setCursorWidth(1.5f); linearLayout3.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 17, 12, 17, 6)); - descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { - doneButton.performClick(); - return true; - } - return false; + descriptionTextView.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { + doneButton.performClick(); + return true; } + return false; }); descriptionTextView.addTextChangedListener(new TextWatcher() { @Override @@ -503,15 +477,12 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), !isPrivate); } linearLayoutTypeContainer.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - radioButtonCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!isPrivate) { - return; - } - isPrivate = false; - updatePrivatePublic(); + radioButtonCell1.setOnClickListener(v -> { + if (!isPrivate) { + return; } + isPrivate = false; + updatePrivatePublic(); }); radioButtonCell2 = new RadioButtonCell(context); @@ -522,15 +493,12 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), isPrivate); } linearLayoutTypeContainer.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - radioButtonCell2.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (isPrivate) { - return; - } - isPrivate = true; - updatePrivatePublic(); + radioButtonCell2.setOnClickListener(v -> { + if (isPrivate) { + return; } + isPrivate = true; + updatePrivatePublic(); }); sectionCell2 = new ShadowSectionCell(context); @@ -602,20 +570,17 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate privateContainer = new TextBlockCell(context); privateContainer.setBackgroundDrawable(Theme.getSelectorDrawable(false)); linkContainer.addView(privateContainer); - privateContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (invite == null) { - return; - } - try { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", invite.link); - clipboard.setPrimaryClip(clip); - Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } + privateContainer.setOnClickListener(v -> { + if (invite == null) { + return; + } + try { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", invite.link); + clipboard.setPrimaryClip(clip); + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); } }); @@ -643,7 +608,7 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate updatePrivatePublic(); } - if (currentChat.creator && currentChat.megagroup) { + if ((currentChat.creator || currentChat.admin_rights != null && currentChat.admin_rights.change_info) && currentChat.megagroup) { headerCell2 = new HeaderCell(context); headerCell2.setText(LocaleController.getString("ChatHistory", R.string.ChatHistory)); headerCell2.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -658,26 +623,20 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate radioButtonCell3.setBackgroundDrawable(Theme.getSelectorDrawable(false)); radioButtonCell3.setTextAndValue(LocaleController.getString("ChatHistoryVisible", R.string.ChatHistoryVisible), LocaleController.getString("ChatHistoryVisibleInfo", R.string.ChatHistoryVisibleInfo), !historyHidden); linearLayoutInviteContainer.addView(radioButtonCell3, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - radioButtonCell3.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - radioButtonCell3.setChecked(true, true); - radioButtonCell4.setChecked(false, true); - historyHidden = false; - } + radioButtonCell3.setOnClickListener(v -> { + radioButtonCell3.setChecked(true, true); + radioButtonCell4.setChecked(false, true); + historyHidden = false; }); radioButtonCell4 = new RadioButtonCell(context); radioButtonCell4.setBackgroundDrawable(Theme.getSelectorDrawable(false)); radioButtonCell4.setTextAndValue(LocaleController.getString("ChatHistoryHidden", R.string.ChatHistoryHidden), LocaleController.getString("ChatHistoryHiddenInfo", R.string.ChatHistoryHiddenInfo), historyHidden); linearLayoutInviteContainer.addView(radioButtonCell4, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - radioButtonCell4.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - radioButtonCell3.setChecked(false, true); - radioButtonCell4.setChecked(true, true); - historyHidden = true; - } + radioButtonCell4.setOnClickListener(v -> { + radioButtonCell3.setChecked(false, true); + radioButtonCell4.setChecked(true, true); + historyHidden = true; }); sectionCell3 = new ShadowSectionCell(context); @@ -708,12 +667,9 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate textCheckCell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); textCheckCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false); container2.addView(textCheckCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - textCheckCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - signMessages = !signMessages; - ((TextCheckCell) v).setChecked(signMessages); - } + textCheckCell.setOnClickListener(v -> { + signMessages = !signMessages; + ((TextCheckCell) v).setChecked(signMessages); }); infoCell = new TextInfoPrivacyCell(context); @@ -730,13 +686,10 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate textCell2.setText(LocaleController.getString("GroupStickers", R.string.GroupStickers), false); } container3.addView(textCell2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - textCell2.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - GroupStickersActivity groupStickersActivity = new GroupStickersActivity(currentChat.id); - groupStickersActivity.setInfo(info); - presentFragment(groupStickersActivity); - } + textCell2.setOnClickListener(v -> { + GroupStickersActivity groupStickersActivity = new GroupStickersActivity(currentChat.id); + groupStickersActivity.setInfo(info); + presentFragment(groupStickersActivity); }); infoCell3 = new TextInfoPrivacyCell(context); @@ -758,31 +711,25 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false); } container3.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - textCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - if (currentChat.megagroup) { - builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); - } else { - builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); - } - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (AndroidUtilities.isTablet()) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, -(long) chatId); - } else { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - } - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), info, true); - finishFragment(); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + textCell.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + if (currentChat.megagroup) { + builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); + } else { + builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); } + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, -(long) chatId); + } else { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + } + MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), info, true); + finishFragment(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); infoCell2 = new TextInfoPrivacyCell(context); @@ -850,24 +797,21 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate @Override public void didUploadedPhoto(final TLRPC.InputFile file, final TLRPC.PhotoSize small, final TLRPC.PhotoSize big, final TLRPC.TL_secureFile secureFile) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - uploadedAvatar = file; - avatar = small.location; - avatarImage.setImage(avatar, "50_50", avatarDrawable); - if (createAfterUpload) { - try { - if (progressDialog != null && progressDialog.isShowing()) { - progressDialog.dismiss(); - progressDialog = null; - } - } catch (Exception e) { - FileLog.e(e); + AndroidUtilities.runOnUIThread(() -> { + uploadedAvatar = file; + avatar = small.location; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + if (createAfterUpload) { + try { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + progressDialog = null; } - donePressed = false; - doneButton.performClick(); + } catch (Exception e) { + FileLog.e(e); } + donePressed = false; + doneButton.performClick(); } }); } @@ -918,75 +862,55 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate loadingAdminedChannels = true; updatePrivatePublic(); TLRPC.TL_channels_getAdminedPublicChannels req = new TLRPC.TL_channels_getAdminedPublicChannels(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingAdminedChannels = false; - if (response != null) { - if (getParentActivity() == null) { - return; - } - for (int a = 0; a < adminedChannelCells.size(); a++) { - linearLayout.removeView(adminedChannelCells.get(a)); - } - adminedChannelCells.clear(); - TLRPC.TL_messages_chats res = (TLRPC.TL_messages_chats) response; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + loadingAdminedChannels = false; + if (response != null) { + if (getParentActivity() == null) { + return; + } + for (int a = 0; a < adminedChannelCells.size(); a++) { + linearLayout.removeView(adminedChannelCells.get(a)); + } + adminedChannelCells.clear(); + TLRPC.TL_messages_chats res = (TLRPC.TL_messages_chats) response; - for (int a = 0; a < res.chats.size(); a++) { - AdminedChannelCell adminedChannelCell = new AdminedChannelCell(getParentActivity(), new View.OnClickListener() { - @Override - public void onClick(View view) { - AdminedChannelCell cell = (AdminedChannelCell) view.getParent(); - final TLRPC.Chat channel = cell.getCurrentChannel(); - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (channel.megagroup) { - builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("RevokeLinkAlert", R.string.RevokeLinkAlert, MessagesController.getInstance(currentAccount).linkPrefix + "/" + channel.username, channel.title))); - } else { - builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("RevokeLinkAlertChannel", R.string.RevokeLinkAlertChannel, MessagesController.getInstance(currentAccount).linkPrefix + "/" + channel.username, channel.title))); - } - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setPositiveButton(LocaleController.getString("RevokeButton", R.string.RevokeButton), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TLRPC.TL_channels_updateUsername req = new TLRPC.TL_channels_updateUsername(); - req.channel = MessagesController.getInputChannel(channel); - req.username = ""; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_boolTrue) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - canCreatePublic = true; - if (nameTextView.length() > 0) { - checkUserName(nameTextView.getText().toString()); - } - updatePrivatePublic(); - } - }); - } - } - }, ConnectionsManager.RequestFlagInvokeAfter); - } - }); - showDialog(builder.create()); - } - }); - adminedChannelCell.setChannel(res.chats.get(a), a == res.chats.size() - 1); - adminedChannelCells.add(adminedChannelCell); - adminnedChannelsLayout.addView(adminedChannelCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 72)); - } - updatePrivatePublic(); + for (int a = 0; a < res.chats.size(); a++) { + AdminedChannelCell adminedChannelCell = new AdminedChannelCell(getParentActivity(), view -> { + AdminedChannelCell cell = (AdminedChannelCell) view.getParent(); + final TLRPC.Chat channel = cell.getCurrentChannel(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (channel.megagroup) { + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("RevokeLinkAlert", R.string.RevokeLinkAlert, MessagesController.getInstance(currentAccount).linkPrefix + "/" + channel.username, channel.title))); + } else { + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("RevokeLinkAlertChannel", R.string.RevokeLinkAlertChannel, MessagesController.getInstance(currentAccount).linkPrefix + "/" + channel.username, channel.title))); } - } - }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString("RevokeButton", R.string.RevokeButton), (dialogInterface, i) -> { + TLRPC.TL_channels_updateUsername req1 = new TLRPC.TL_channels_updateUsername(); + req1.channel = MessagesController.getInputChannel(channel); + req1.username = ""; + ConnectionsManager.getInstance(currentAccount).sendRequest(req1, (response1, error1) -> { + if (response1 instanceof TLRPC.TL_boolTrue) { + AndroidUtilities.runOnUIThread(() -> { + canCreatePublic = true; + if (nameTextView.length() > 0) { + checkUserName(nameTextView.getText().toString()); + } + updatePrivatePublic(); + }); + } + }, ConnectionsManager.RequestFlagInvokeAfter); + }); + showDialog(builder.create()); + }); + adminedChannelCell.setChannel(res.chats.get(a), a == res.chats.size() - 1); + adminedChannelCells.add(adminedChannelCell); + adminnedChannelsLayout.addView(adminedChannelCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 72)); + } + updatePrivatePublic(); } - }); + })); } private void updatePrivatePublic() { @@ -1116,42 +1040,31 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate checkTextView.setTag(Theme.key_windowBackgroundWhiteGrayText8); checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText8)); lastCheckName = name; - checkRunnable = new Runnable() { - @Override - public void run() { - TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); - req.username = name; - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); - checkReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkReqId = 0; - if (lastCheckName != null && lastCheckName.equals(name)) { - if (error == null && response instanceof TLRPC.TL_boolTrue) { - checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name)); - checkTextView.setTag(Theme.key_windowBackgroundWhiteGreenText); - checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); - lastNameAvailable = true; - } else { - if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { - canCreatePublic = false; - loadAdminedChannels(); - } else { - checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); - } - checkTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); - checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); - lastNameAvailable = false; - } - } - } - }); + checkRunnable = () -> { + TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); + req.username = name; + req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + checkReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + checkReqId = 0; + if (lastCheckName != null && lastCheckName.equals(name)) { + if (error == null && response instanceof TLRPC.TL_boolTrue) { + checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name)); + checkTextView.setTag(Theme.key_windowBackgroundWhiteGreenText); + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); + lastNameAvailable = true; + } else { + if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + canCreatePublic = false; + loadAdminedChannels(); + } else { + checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + } + checkTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + lastNameAvailable = false; } - }, ConnectionsManager.RequestFlagFailOnServerErrors); - } + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); }; AndroidUtilities.runOnUIThread(checkRunnable, 300); return true; @@ -1164,45 +1077,34 @@ public class ChannelEditInfoActivity extends BaseFragment implements ImageUpdate loadingInvite = true; TLRPC.TL_channels_exportInvite req = new TLRPC.TL_channels_exportInvite(); req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - invite = (TLRPC.ExportedChatInvite) response; - if (info != null) { - info.exported_invite = invite; - } - } - loadingInvite = false; - if (privateContainer != null) { - privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + invite = (TLRPC.ExportedChatInvite) response; + if (info != null) { + info.exported_invite = invite; + } } - }); + loadingInvite = false; + if (privateContainer != null) { + privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); + } + })); } @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (avatarImage != null) { - avatarDrawable.setInfo(5, nameTextView.length() > 0 ? nameTextView.getText().toString() : null, null, false); - avatarImage.invalidate(); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (avatarImage != null) { + avatarDrawable.setInfo(5, nameTextView.length() > 0 ? nameTextView.getText().toString() : null, null, false); + avatarImage.invalidate(); + } - if (adminnedChannelsLayout != null) { - int count = adminnedChannelsLayout.getChildCount(); - for (int a = 0; a < count; a++) { - View child = adminnedChannelsLayout.getChildAt(a); - if (child instanceof AdminedChannelCell) { - ((AdminedChannelCell) child).update(); - } + if (adminnedChannelsLayout != null) { + int count = adminnedChannelsLayout.getChildCount(); + for (int a = 0; a < count; a++) { + View child = adminnedChannelsLayout.getChildAt(a); + if (child instanceof AdminedChannelCell) { + ((AdminedChannelCell) child).update(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java index 0002f8238..b7c88f728 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; @@ -42,7 +41,6 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -67,7 +65,6 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; @@ -187,7 +184,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe blockedEmptyRow = rowCount++; } } else if (type == 1) { - if (currentChat.creator && currentChat.megagroup) { + if ((currentChat.creator || currentChat.admin_rights != null && currentChat.admin_rights.change_info) && currentChat.megagroup) { changeAddHeaderRow = rowCount++; changeAddRadio1Row = rowCount++; changeAddRadio2Row = rowCount++; @@ -339,183 +336,163 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (position == addNewRow) { - if (type == 0) { - Bundle bundle = new Bundle(); - bundle.putInt("chat_id", chatId); - bundle.putInt("type", 2); - bundle.putInt("selectType", 2); - presentFragment(new ChannelUsersActivity(bundle)); - } else if (type == 1) { - Bundle bundle = new Bundle(); - bundle.putInt("chat_id", chatId); - bundle.putInt("type", 2); - bundle.putInt("selectType", 1); - presentFragment(new ChannelUsersActivity(bundle)); - } else if (type == 2) { - Bundle args = new Bundle(); - args.putBoolean("onlyUsers", true); - args.putBoolean("destroyAfterSelect", true); - args.putBoolean("returnAsResult", true); - args.putBoolean("needForwardCount", false); - args.putString("selectAlertString", LocaleController.getString("ChannelAddTo", R.string.ChannelAddTo)); - ContactsActivity fragment = new ContactsActivity(args); - fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() { - @Override - public void didSelectContact(TLRPC.User user, String param, ContactsActivity activity) { - MessagesController.getInstance(currentAccount).addUserToChat(chatId, user, null, param != null ? Utilities.parseInt(param) : 0, null, ChannelUsersActivity.this); - } - }); - presentFragment(fragment); + listView.setOnItemClickListener((view, position) -> { + if (position == addNewRow) { + if (type == 0) { + Bundle bundle = new Bundle(); + bundle.putInt("chat_id", chatId); + bundle.putInt("type", 2); + bundle.putInt("selectType", 2); + presentFragment(new ChannelUsersActivity(bundle)); + } else if (type == 1) { + Bundle bundle = new Bundle(); + bundle.putInt("chat_id", chatId); + bundle.putInt("type", 2); + bundle.putInt("selectType", 1); + presentFragment(new ChannelUsersActivity(bundle)); + } else if (type == 2) { + Bundle args = new Bundle(); + args.putBoolean("onlyUsers", true); + args.putBoolean("destroyAfterSelect", true); + args.putBoolean("returnAsResult", true); + args.putBoolean("needForwardCount", false); + args.putString("selectAlertString", LocaleController.getString("ChannelAddTo", R.string.ChannelAddTo)); + ContactsActivity fragment = new ContactsActivity(args); + fragment.setDelegate((user, param, activity) -> MessagesController.getInstance(currentAccount).addUserToChat(chatId, user, null, param != null ? Utilities.parseInt(param) : 0, null, ChannelUsersActivity.this)); + presentFragment(fragment); + } + } else if (position == addNew2Row) { + presentFragment(new GroupInviteActivity(chatId)); + } else if (position == changeAddRadio1Row || position == changeAddRadio2Row) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); + if (chat == null) { + return; + } + boolean changed = false; + if (position == 1 && !chat.democracy) { + chat.democracy = true; + changed = true; + } else if (position == 2 && chat.democracy) { + chat.democracy = false; + changed = true; + } + if (changed) { + MessagesController.getInstance(currentAccount).toogleChannelInvites(chatId, chat.democracy); + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof RadioCell) { + int num = (Integer) child.getTag(); + ((RadioCell) child).setChecked(num == 0 && chat.democracy || num == 1 && !chat.democracy, true); + } } - } else if (position == addNew2Row) { - presentFragment(new GroupInviteActivity(chatId)); - } else if (position == changeAddRadio1Row || position == changeAddRadio2Row) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); - if (chat == null) { - return; - } - boolean changed = false; - if (position == 1 && !chat.democracy) { - chat.democracy = true; - changed = true; - } else if (position == 2 && chat.democracy) { - chat.democracy = false; - changed = true; - } - if (changed) { - MessagesController.getInstance(currentAccount).toogleChannelInvites(chatId, chat.democracy); - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof RadioCell) { - int num = (Integer) child.getTag(); - ((RadioCell) child).setChecked(num == 0 && chat.democracy || num == 1 && !chat.democracy, true); - } + } + } else { + TLRPC.TL_channelBannedRights banned_rights = null; + TLRPC.TL_channelAdminRights admin_rights = null; + final TLRPC.ChannelParticipant participant; + int user_id = 0; + int promoted_by = 0; + boolean canEditAdmin = false; + if (listView.getAdapter() == listViewAdapter) { + participant = listViewAdapter.getItem(position); + if (participant != null) { + user_id = participant.user_id; + banned_rights = participant.banned_rights; + admin_rights = participant.admin_rights; + canEditAdmin = !(participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipantCreator) || participant.can_edit; + if (participant instanceof TLRPC.TL_channelParticipantCreator) { + admin_rights = new TLRPC.TL_channelAdminRights(); + admin_rights.change_info = admin_rights.post_messages = admin_rights.edit_messages = + admin_rights.delete_messages = admin_rights.ban_users = admin_rights.invite_users = + admin_rights.invite_link = admin_rights.pin_messages = admin_rights.add_admins = true; } } } else { - TLRPC.TL_channelBannedRights banned_rights = null; - TLRPC.TL_channelAdminRights admin_rights = null; - final TLRPC.ChannelParticipant participant; - int user_id = 0; - int promoted_by = 0; - boolean canEditAdmin = false; - if (listView.getAdapter() == listViewAdapter) { - participant = listViewAdapter.getItem(position); - if (participant != null) { - user_id = participant.user_id; - banned_rights = participant.banned_rights; - admin_rights = participant.admin_rights; - canEditAdmin = !(participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipantCreator) || participant.can_edit; - if (participant instanceof TLRPC.TL_channelParticipantCreator) { - admin_rights = new TLRPC.TL_channelAdminRights(); - admin_rights.change_info = admin_rights.post_messages = admin_rights.edit_messages = - admin_rights.delete_messages = admin_rights.ban_users = admin_rights.invite_users = - admin_rights.invite_link = admin_rights.pin_messages = admin_rights.add_admins = true; - } + TLObject object = searchListViewAdapter.getItem(position); + if (object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) object; + MessagesController.getInstance(currentAccount).putUser(user, false); + participant = participantsMap.get(user_id = user.id); + } else if (object instanceof TLRPC.ChannelParticipant) { + participant = (TLRPC.ChannelParticipant) object; + } else { + participant = null; + } + if (participant != null) { + user_id = participant.user_id; + canEditAdmin = !(participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipantCreator) || participant.can_edit; + banned_rights = participant.banned_rights; + admin_rights = participant.admin_rights; + } else { + canEditAdmin = true; + } + } + if (user_id != 0) { + if (selectType != 0) { + if (currentChat.megagroup || selectType == 1) { + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, chatId, admin_rights, banned_rights, selectType == 1 ? 0 : 1, canEditAdmin); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> { + if (participant != null) { + participant.admin_rights = rightsAdmin; + participant.banned_rights = rightsBanned; + TLRPC.ChannelParticipant p = participantsMap.get(participant.user_id); + if (p != null) { + p.admin_rights = rightsAdmin; + p.banned_rights = rightsBanned; + } + } + removeSelfFromStack(); + }); + presentFragment(fragment); + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); + MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); + finishFragment(); } } else { - TLObject object = searchListViewAdapter.getItem(position); - if (object instanceof TLRPC.User) { - TLRPC.User user = (TLRPC.User) object; - MessagesController.getInstance(currentAccount).putUser(user, false); - participant = participantsMap.get(user_id = user.id); - } else if (object instanceof TLRPC.ChannelParticipant) { - participant = (TLRPC.ChannelParticipant) object; - } else { - participant = null; + boolean canEdit = false; + if (type == 1) { + canEdit = user_id != UserConfig.getInstance(currentAccount).getClientUserId() && (currentChat.creator || canEditAdmin); + } else if (type == 0) { + canEdit = ChatObject.canBlockUsers(currentChat); } - if (participant != null) { - user_id = participant.user_id; - canEditAdmin = !(participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipantCreator) || participant.can_edit; - banned_rights = participant.banned_rights; - admin_rights = participant.admin_rights; + if (type != 1 && !currentChat.megagroup || type == 2 && selectType == 0) { + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ProfileActivity(args)); } else { - canEditAdmin = true; - } - } - if (user_id != 0) { - if (selectType != 0) { - if (currentChat.megagroup || selectType == 1) { - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, chatId, admin_rights, banned_rights, selectType == 1 ? 0 : 1, canEditAdmin); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - if (participant != null) { - participant.admin_rights = rightsAdmin; - participant.banned_rights = rightsBanned; - TLRPC.ChannelParticipant p = participantsMap.get(participant.user_id); - if (p != null) { - p.admin_rights = rightsAdmin; - p.banned_rights = rightsBanned; - } - } - removeSelfFromStack(); + if (banned_rights == null) { + banned_rights = new TLRPC.TL_channelBannedRights(); + banned_rights.view_messages = true; + banned_rights.send_stickers = true; + banned_rights.send_media = true; + banned_rights.embed_links = true; + banned_rights.send_messages = true; + banned_rights.send_games = true; + banned_rights.send_inline = true; + banned_rights.send_gifs = true; + } + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, chatId, admin_rights, banned_rights, type == 1 ? 0 : 1, canEdit); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> { + if (participant != null) { + participant.admin_rights = rightsAdmin; + participant.banned_rights = rightsBanned; + TLRPC.ChannelParticipant p = participantsMap.get(participant.user_id); + if (p != null) { + p.admin_rights = rightsAdmin; + p.banned_rights = rightsBanned; } - }); - presentFragment(fragment); - } else { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); - finishFragment(); - } - } else { - boolean canEdit = false; - if (type == 1) { - canEdit = user_id != UserConfig.getInstance(currentAccount).getClientUserId() && (currentChat.creator || canEditAdmin); - } else if (type == 0) { - canEdit = ChatObject.canBlockUsers(currentChat); - } - if (type != 1 && !currentChat.megagroup || type == 2 && selectType == 0) { - Bundle args = new Bundle(); - args.putInt("user_id", user_id); - presentFragment(new ProfileActivity(args)); - } else { - if (banned_rights == null) { - banned_rights = new TLRPC.TL_channelBannedRights(); - banned_rights.view_messages = true; - banned_rights.send_stickers = true; - banned_rights.send_media = true; - banned_rights.embed_links = true; - banned_rights.send_messages = true; - banned_rights.send_games = true; - banned_rights.send_inline = true; - banned_rights.send_gifs = true; } - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, chatId, admin_rights, banned_rights, type == 1 ? 0 : 1, canEdit); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - if (participant != null) { - participant.admin_rights = rightsAdmin; - participant.banned_rights = rightsBanned; - TLRPC.ChannelParticipant p = participantsMap.get(participant.user_id); - if (p != null) { - p.admin_rights = rightsAdmin; - p.banned_rights = rightsBanned; - } - } - } - }); - presentFragment(fragment); - } + }); + presentFragment(fragment); } } } } }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - return !(getParentActivity() == null || listView.getAdapter() != listViewAdapter) && createMenuForParticipant(listViewAdapter.getItem(position), false); - - } - }); + listView.setOnItemLongClickListener((view, position) -> !(getParentActivity() == null || listView.getAdapter() != listViewAdapter) && createMenuForParticipant(listViewAdapter.getItem(position), false)); if (searchItem != null) { listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -591,61 +568,55 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(items.toArray(new CharSequence[actions.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, final int i) { - if (actions.get(i) == 2) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); - for (int a = 0; a < participants.size(); a++) { - TLRPC.ChannelParticipant p = participants.get(a); - if (p.user_id == participant.user_id) { - participants.remove(a); - updateRows(); - listViewAdapter.notifyDataSetChanged(); - break; - } + builder.setItems(items.toArray(new CharSequence[actions.size()]), (dialogInterface, i) -> { + if (actions.get(i) == 2) { + MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, user, null); + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChannelParticipant p = participants.get(a); + if (p.user_id == participant.user_id) { + participants.remove(a); + updateRows(); + listViewAdapter.notifyDataSetChanged(); + break; } - } else { - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user.id, chatId, participant.admin_rights, participant.banned_rights, actions.get(i), true); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - if (actions.get(i) == 0) { - for (int a = 0; a < participants.size(); a++) { - TLRPC.ChannelParticipant p = participants.get(a); - if (p.user_id == participant.user_id) { - TLRPC.ChannelParticipant newPart; - if (rights == 1) { - newPart = new TLRPC.TL_channelParticipantAdmin(); - } else { - newPart = new TLRPC.TL_channelParticipant(); - } - newPart.admin_rights = rightsAdmin; - newPart.banned_rights = rightsBanned; - newPart.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); - newPart.user_id = participant.user_id; - newPart.date = participant.date; - participants.set(a, newPart); - break; - } + } + } else { + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user.id, chatId, participant.admin_rights, participant.banned_rights, actions.get(i), true); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> { + if (actions.get(i) == 0) { + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChannelParticipant p = participants.get(a); + if (p.user_id == participant.user_id) { + TLRPC.ChannelParticipant newPart; + if (rights == 1) { + newPart = new TLRPC.TL_channelParticipantAdmin(); + } else { + newPart = new TLRPC.TL_channelParticipant(); } - } else if (actions.get(i) == 1) { - if (rights == 0) { - for (int a = 0; a < participants.size(); a++) { - TLRPC.ChannelParticipant p = participants.get(a); - if (p.user_id == participant.user_id) { - participants.remove(a); - updateRows(); - listViewAdapter.notifyDataSetChanged(); - break; - } - } + newPart.admin_rights = rightsAdmin; + newPart.banned_rights = rightsBanned; + newPart.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); + newPart.user_id = participant.user_id; + newPart.date = participant.date; + participants.set(a, newPart); + break; + } + } + } else if (actions.get(i) == 1) { + if (rights == 0) { + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChannelParticipant p = participants.get(a); + if (p.user_id == participant.user_id) { + participants.remove(a); + updateRows(); + listViewAdapter.notifyDataSetChanged(); + break; } } } - }); - presentFragment(fragment); - } + } + }); + presentFragment(fragment); } }); showDialog(builder.create()); @@ -666,41 +637,32 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe return false; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - if (type == 0) { - participants.remove(participant); - updateRows(); - listViewAdapter.notifyDataSetChanged(); - TLRPC.TL_channels_editBanned req = new TLRPC.TL_channels_editBanned(); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(participant.user_id); - req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); - req.banned_rights = new TLRPC.TL_channelBannedRights(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (response != null) { - final TLRPC.Updates updates = (TLRPC.Updates) response; - MessagesController.getInstance(currentAccount).processUpdates(updates, false); - if (!updates.chats.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.Chat chat = updates.chats.get(0); - MessagesController.getInstance(currentAccount).loadFullChat(chat.id, 0, true); - } - }, 1000); - } - } + builder.setItems(items, (dialogInterface, i) -> { + if (i == 0) { + if (type == 0) { + participants.remove(participant); + updateRows(); + listViewAdapter.notifyDataSetChanged(); + TLRPC.TL_channels_editBanned req = new TLRPC.TL_channels_editBanned(); + req.user_id = MessagesController.getInstance(currentAccount).getInputUser(participant.user_id); + req.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); + req.banned_rights = new TLRPC.TL_channelBannedRights(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + final TLRPC.Updates updates = (TLRPC.Updates) response; + MessagesController.getInstance(currentAccount).processUpdates(updates, false); + if (!updates.chats.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.Chat chat = updates.chats.get(0); + MessagesController.getInstance(currentAccount).loadFullChat(chat.id, 0, true); + }, 1000); } - }); - } else if (type == 1) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), new TLRPC.TL_channelAdminRights(), currentChat.megagroup, ChannelUsersActivity.this); - } else if (type == 2) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), null); - } + } + }); + } else if (type == 1) { + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), new TLRPC.TL_channelAdminRights(), currentChat.megagroup, ChannelUsersActivity.this); + } else if (type == 2) { + MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), null); } } }); @@ -715,12 +677,9 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; boolean byChannelUsers = (Boolean) args[2]; if (chatFull.id == chatId && !byChannelUsers) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - firstEndReached = false; - getChannelParticipants(0, 200); - } + AndroidUtilities.runOnUIThread(() -> { + firstEndReached = false; + getChannelParticipants(0, 200); }); } } @@ -764,123 +723,109 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe req.filter.q = ""; req.offset = offset; req.limit = count; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - boolean changeFirst = !firstLoaded; - loadingUsers = false; - firstLoaded = true; - if (emptyView != null) { - emptyView.showTextView(); - } - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - int selfId = UserConfig.getInstance(currentAccount).getClientUserId(); - if (selectType != 0) { - for (int a = 0; a < res.participants.size(); a++) { - if (res.participants.get(a).user_id == selfId) { - res.participants.remove(a); - break; - } - } - } - if (type == 0) { - if (byEndReached) { - participants2 = res.participants; - } else { - participants2 = new ArrayList<>(); - participantsMap.clear(); - participants = res.participants; - if (changeFirst) { - firstLoaded = false; - } - firstEndReached = true; - getChannelParticipants(0, 200); - } - } else { - participantsMap.clear(); - participants = res.participants; - } - for (int a = 0; a < res.participants.size(); a++) { - TLRPC.ChannelParticipant participant = res.participants.get(a); - participantsMap.put(participant.user_id, participant); - } - try { - if (type == 0 || type == 2) { - Collections.sort(res.participants, new Comparator() { - @Override - public int compare(TLRPC.ChannelParticipant lhs, TLRPC.ChannelParticipant rhs) { - TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(rhs.user_id); - TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(lhs.user_id); - int status1 = 0; - int status2 = 0; - if (user1 != null && user1.status != null) { - if (user1.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - status1 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; - } else { - status1 = user1.status.expires; - } - } - if (user2 != null && user2.status != null) { - if (user2.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - status2 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; - } else { - status2 = user2.status.expires; - } - } - if (status1 > 0 && status2 > 0) { - if (status1 > status2) { - return 1; - } else if (status1 < status2) { - return -1; - } - return 0; - } else if (status1 < 0 && status2 < 0) { - if (status1 > status2) { - return 1; - } else if (status1 < status2) { - return -1; - } - return 0; - } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { - return -1; - } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { - return 1; - } - return 0; - } - }); - } else if (type == 1) { - Collections.sort(res.participants, new Comparator() { - @Override - public int compare(TLRPC.ChannelParticipant lhs, TLRPC.ChannelParticipant rhs) { - int type1 = getChannelAdminParticipantType(lhs); - int type2 = getChannelAdminParticipantType(rhs); - if (type1 > type2) { - return 1; - } else if (type1 < type2) { - return -1; - } - return 0; - } - }); - } - } catch (Exception e) { - FileLog.e(e); - } - } - updateRows(); - if (listViewAdapter != null) { - listViewAdapter.notifyDataSetChanged(); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + boolean changeFirst = !firstLoaded; + loadingUsers = false; + firstLoaded = true; + if (emptyView != null) { + emptyView.showTextView(); + } + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + int selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + if (selectType != 0) { + for (int a = 0; a < res.participants.size(); a++) { + if (res.participants.get(a).user_id == selfId) { + res.participants.remove(a); + break; } } - }); + } + if (type == 0) { + if (byEndReached) { + participants2 = res.participants; + } else { + participants2 = new ArrayList<>(); + participantsMap.clear(); + participants = res.participants; + if (changeFirst) { + firstLoaded = false; + } + firstEndReached = true; + getChannelParticipants(0, 200); + } + } else { + participantsMap.clear(); + participants = res.participants; + } + for (int a = 0; a < res.participants.size(); a++) { + TLRPC.ChannelParticipant participant = res.participants.get(a); + participantsMap.put(participant.user_id, participant); + } + try { + if (type == 0 || type == 2) { + Collections.sort(res.participants, (lhs, rhs) -> { + TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(rhs.user_id); + TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(lhs.user_id); + int status1 = 0; + int status2 = 0; + if (user1 != null && user1.status != null) { + if (user1.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + status1 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; + } else { + status1 = user1.status.expires; + } + } + if (user2 != null && user2.status != null) { + if (user2.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + status2 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; + } else { + status2 = user2.status.expires; + } + } + if (status1 > 0 && status2 > 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 < 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { + return -1; + } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { + return 1; + } + return 0; + }); + } else if (type == 1) { + Collections.sort(res.participants, (lhs, rhs) -> { + int type1 = getChannelAdminParticipantType(lhs); + int type2 = getChannelAdminParticipantType(rhs); + if (type1 > type2) { + return 1; + } else if (type1 < type2) { + return -1; + } + return 0; + }); + } + } catch (Exception e) { + FileLog.e(e); + } } - }); + updateRows(); + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + })); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -960,82 +905,73 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchAdapterHelper.queryServerSearch(query, selectType != 0, false, true, true, chatId, type == 0); - if (selectType == 1) { - final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(new ArrayList(), new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + AndroidUtilities.runOnUIThread(() -> { + searchAdapterHelper.queryServerSearch(query, selectType != 0, false, true, true, chatId, type == 0); + if (selectType == 1) { + final ArrayList contactsCopy = new ArrayList<>(ContactsController.getInstance(currentAccount).contacts); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>(), new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList resultArray = new ArrayList<>(); - ArrayList resultArrayNames = new ArrayList<>(); + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); - for (int a = 0; a < contactsCopy.size(); a++) { - TLRPC.TL_contact contact = contactsCopy.get(a); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); - if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - continue; - } - - String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (user.username != null && user.username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray.add(user); - break; - } - } - } - - updateSearchResults(resultArray, resultArrayNames); + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.TL_contact contact = contactsCopy.get(a); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); + if (user.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + continue; } - }); - } + + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(user); + break; + } + } + } + + updateSearchResults(resultArray, resultArrayNames); + }); } }); } private void updateSearchResults(final ArrayList users, final ArrayList names) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchResult = users; - searchResultNames = names; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); }); } @@ -1157,16 +1093,13 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe case 0: view = new ManageChatUserCell(mContext, 2, selectType == 0); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - TLObject object = getItem((Integer) cell.getTag()); - if (object instanceof TLRPC.ChannelParticipant) { - TLRPC.ChannelParticipant participant = (TLRPC.ChannelParticipant) getItem((Integer) cell.getTag()); - return createMenuForParticipant(participant, !click); - } else { - return false; - } + ((ManageChatUserCell) view).setDelegate((cell, click) -> { + TLObject object = getItem((Integer) cell.getTag()); + if (object instanceof TLRPC.ChannelParticipant) { + TLRPC.ChannelParticipant participant = (TLRPC.ChannelParticipant) getItem((Integer) cell.getTag()); + return createMenuForParticipant(participant, !click); + } else { + return false; } }); break; @@ -1347,12 +1280,9 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe case 0: view = new ManageChatUserCell(mContext, type == 0 ? 8 : 1, selectType == 0); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - TLRPC.ChannelParticipant participant = listViewAdapter.getItem((Integer) cell.getTag()); - return createMenuForParticipant(participant, !click); - } + ((ManageChatUserCell) view).setDelegate((cell, click) -> { + TLRPC.ChannelParticipant participant = listViewAdapter.getItem((Integer) cell.getTag()); + return createMenuForParticipant(participant, !click); }); break; case 1: @@ -1574,16 +1504,13 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof ManageChatUserCell) { - ((ManageChatUserCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof ManageChatUserCell) { + ((ManageChatUserCell) child).update(0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 1f21837aa..8f8f73892 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -23,9 +23,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; -import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Outline; @@ -41,9 +39,7 @@ import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.provider.ContactsContract; import android.provider.MediaStore; -import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; import android.text.Spannable; import android.text.SpannableString; @@ -54,7 +50,6 @@ import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.URLSpan; -import android.util.Base64; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -78,6 +73,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.BuildConfig; @@ -98,9 +95,7 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.browser.Browser; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.messenger.support.SparseLongArray; -import org.telegram.messenger.support.widget.DefaultItemAnimator; import org.telegram.messenger.support.widget.GridLayoutManager; import org.telegram.messenger.support.widget.GridLayoutManagerFixed; import org.telegram.messenger.support.widget.LinearLayoutManager; @@ -109,8 +104,6 @@ import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLoader; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; @@ -148,7 +141,6 @@ import org.telegram.messenger.ImageReceiver; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.ChatBigEmptyView; -import org.telegram.ui.Components.ChatItemAnimator; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CorrectlyMeasuringTextView; import org.telegram.ui.Components.EmbedBottomSheet; @@ -176,7 +168,6 @@ import org.telegram.ui.Components.voip.VoIPHelper; import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; import java.io.FileWriter; import java.net.URLDecoder; import java.util.ArrayList; @@ -641,12 +632,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); final MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); - messagesStorage.getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentChat = messagesStorage.getChat(chatId); - countDownLatch.countDown(); - } + messagesStorage.getStorageQueue().postRunnable(() -> { + currentChat = messagesStorage.getChat(chatId); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -673,12 +661,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentUser == null) { final MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); final CountDownLatch countDownLatch = new CountDownLatch(1); - messagesStorage.getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentUser = messagesStorage.getUser(userId); - countDownLatch.countDown(); - } + messagesStorage.getStorageQueue().postRunnable(() -> { + currentUser = messagesStorage.getUser(userId); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -701,12 +686,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); if (currentEncryptedChat == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); - messagesStorage.getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentEncryptedChat = messagesStorage.getEncryptedChat(encId); - countDownLatch.countDown(); - } + messagesStorage.getStorageQueue().postRunnable(() -> { + currentEncryptedChat = messagesStorage.getEncryptedChat(encId); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -722,12 +704,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not currentUser = MessagesController.getInstance(currentAccount).getUser(currentEncryptedChat.user_id); if (currentUser == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); - messagesStorage.getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentUser = messagesStorage.getUser(currentEncryptedChat.user_id); - countDownLatch.countDown(); - } + messagesStorage.getStorageQueue().postRunnable(() -> { + currentUser = messagesStorage.getUser(currentEncryptedChat.user_id); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -860,7 +839,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (currentUser != null) { - userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.contains(currentUser.id); + userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.indexOfKey(currentUser.id) >= 0; } if (AndroidUtilities.isTablet()) { @@ -1087,28 +1066,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); } } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (id != clear_history) { - if (isChat) { - if (ChatObject.isNotInChat(currentChat)) { - MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); - } else { - MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -dialog_id, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); - } - } else { + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (id != clear_history) { + if (isChat) { + if (ChatObject.isNotInChat(currentChat)) { MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); + } else { + MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -dialog_id, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); } - finishFragment(); } else { - if (ChatObject.isChannel(currentChat) && info != null && info.pinned_msg_id != 0) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("pin_" + dialog_id, info.pinned_msg_id).commit(); - updatePinnedMessageView(true); - } - MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 1); + MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); } + finishFragment(); + } else { + if (ChatObject.isChannel(currentChat) && info != null && info.pinned_msg_id != 0) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().putInt("pin_" + dialog_id, info.pinned_msg_id).commit(); + updatePinnedMessageView(true); + } + MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 1); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -1314,13 +1290,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!openSearchKeyboard) { return; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchWas = false; - searchItem.getSearchField().requestFocus(); - AndroidUtilities.showKeyboard(searchItem.getSearchField()); - } + AndroidUtilities.runOnUIThread(() -> { + searchWas = false; + searchItem.getSearchField().requestFocus(); + AndroidUtilities.showKeyboard(searchItem.getSearchField()); }, 300); } @@ -1441,12 +1414,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); selectedMessagesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); - selectedMessagesCountTextView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + selectedMessagesCountTextView.setOnTouchListener((v, event) -> true); if (currentEncryptedChat == null) { actionModeViews.add(actionMode.addItemWithWidth(edit, R.drawable.group_edit, AndroidUtilities.dp(54))); @@ -1644,12 +1612,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (scrollToPositionOnRecreate != -1) { final int scrollTo = scrollToPositionOnRecreate; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - chatLayoutManager.scrollToPositionWithOffset(scrollTo, scrollToOffsetOnRecreate); - } - }); + AndroidUtilities.runOnUIThread(() -> chatLayoutManager.scrollToPositionWithOffset(scrollTo, scrollToOffsetOnRecreate)); globalIgnoreLayout = true; scrollToPositionOnRecreate = -1; @@ -1774,12 +1737,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not emptyViewContainer = new FrameLayout(context); emptyViewContainer.setVisibility(View.INVISIBLE); contentView.addView(emptyViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); - emptyViewContainer.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + emptyViewContainer.setOnTouchListener((v, event) -> true); if (currentEncryptedChat == null) { if (currentUser != null && currentUser.self) { @@ -2554,22 +2512,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not floatingDateView = new ChatActionCell(context); floatingDateView.setAlpha(0.0f); contentView.addView(floatingDateView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 4, 0, 0)); - floatingDateView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (floatingDateView.getAlpha() == 0) { - return; - } - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis((long) floatingDateView.getCustomDate() * 1000); - int year = calendar.get(Calendar.YEAR); - int monthOfYear = calendar.get(Calendar.MONTH); - int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); - - calendar.clear(); - calendar.set(year, monthOfYear, dayOfMonth); - jumpToDate((int) (calendar.getTime().getTime() / 1000)); + floatingDateView.setOnClickListener(view -> { + if (floatingDateView.getAlpha() == 0) { + return; } + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis((long) floatingDateView.getCustomDate() * 1000); + int year = calendar.get(Calendar.YEAR); + int monthOfYear = calendar.get(Calendar.MONTH); + int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); + + calendar.clear(); + calendar.set(year, monthOfYear, dayOfMonth); + jumpToDate((int) (calendar.getTime().getTime() / 1000)); }); if (ChatObject.isChannel(currentChat)) { @@ -2580,12 +2535,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageView.setBackgroundResource(R.drawable.blockpanel); pinnedMessageView.getBackground().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelBackground), PorterDuff.Mode.MULTIPLY)); contentView.addView(pinnedMessageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.TOP | Gravity.LEFT)); - pinnedMessageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - wasManualScroll = true; - scrollToMessageId(info.pinned_msg_id, 0, true, 0, false); - } + pinnedMessageView.setOnClickListener(v -> { + wasManualScroll = true; + scrollToMessageId(info.pinned_msg_id, 0, true, 0, false); }); pinnedLineView = new View(context); @@ -2611,29 +2563,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not closePinned.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelClose), PorterDuff.Mode.MULTIPLY)); closePinned.setScaleType(ImageView.ScaleType.CENTER); pinnedMessageView.addView(closePinned, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); - closePinned.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getParentActivity() == null) { - return; - } - if (currentChat.creator || currentChat.admin_rights != null && (currentChat.megagroup && currentChat.admin_rights.pin_messages || !currentChat.megagroup && currentChat.admin_rights.edit_messages)) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, 0, false); - } - }); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("pin_" + dialog_id, info.pinned_msg_id).commit(); - updatePinnedMessageView(true); - } + closePinned.setOnClickListener(v -> { + if (getParentActivity() == null) { + return; + } + if (currentChat.creator || currentChat.admin_rights != null && (currentChat.megagroup && currentChat.admin_rights.pin_messages || !currentChat.megagroup && currentChat.admin_rights.edit_messages)) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, 0, false)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().putInt("pin_" + dialog_id, info.pinned_msg_id).commit(); + updatePinnedMessageView(true); } }); } @@ -2657,14 +2601,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not addToContactsButton.setGravity(Gravity.CENTER); addToContactsButton.setText(LocaleController.getString("AddContactChat", R.string.AddContactChat)); reportSpamView.addView(addToContactsButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); - addToContactsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Bundle args = new Bundle(); - args.putInt("user_id", currentUser.id); - args.putBoolean("addContact", true); - presentFragment(new ContactAddActivity(args)); - } + addToContactsButton.setOnClickListener(v -> { + Bundle args = new Bundle(); + args.putInt("user_id", currentUser.id); + args.putBoolean("addContact", true); + presentFragment(new ContactAddActivity(args)); }); reportSpamContainer = new FrameLayout(context); @@ -2684,44 +2625,38 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not reportSpamButton.setGravity(Gravity.CENTER); reportSpamButton.setPadding(AndroidUtilities.dp(50), 0, AndroidUtilities.dp(50), 0); reportSpamContainer.addView(reportSpamButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); - reportSpamButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { - builder.setMessage(LocaleController.getString("ReportSpamAlertChannel", R.string.ReportSpamAlertChannel)); - } else if (currentChat != null) { - builder.setMessage(LocaleController.getString("ReportSpamAlertGroup", R.string.ReportSpamAlertGroup)); - } else { - builder.setMessage(LocaleController.getString("ReportSpamAlert", R.string.ReportSpamAlert)); - } - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (currentUser != null) { - MessagesController.getInstance(currentAccount).blockUser(currentUser.id); - } - MessagesController.getInstance(currentAccount).reportSpam(dialog_id, currentUser, currentChat, currentEncryptedChat); - updateSpamView(); - if (currentChat != null) { - if (ChatObject.isNotInChat(currentChat)) { - MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); - } else { - MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -dialog_id, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); - } - } else { - MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); - } - finishFragment(); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + reportSpamButton.setOnClickListener(v -> { + if (getParentActivity() == null) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { + builder.setMessage(LocaleController.getString("ReportSpamAlertChannel", R.string.ReportSpamAlertChannel)); + } else if (currentChat != null) { + builder.setMessage(LocaleController.getString("ReportSpamAlertGroup", R.string.ReportSpamAlertGroup)); + } else { + builder.setMessage(LocaleController.getString("ReportSpamAlert", R.string.ReportSpamAlert)); + } + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (currentUser != null) { + MessagesController.getInstance(currentAccount).blockUser(currentUser.id); + } + MessagesController.getInstance(currentAccount).reportSpam(dialog_id, currentUser, currentChat, currentEncryptedChat); + updateSpamView(); + if (currentChat != null) { + if (ChatObject.isNotInChat(currentChat)) { + MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); + } else { + MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -dialog_id, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); + } + } else { + MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); + } + finishFragment(); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); closeReportSpam = new ImageView(context); @@ -2729,12 +2664,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not closeReportSpam.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelClose), PorterDuff.Mode.MULTIPLY)); closeReportSpam.setScaleType(ImageView.ScaleType.CENTER); reportSpamContainer.addView(closeReportSpam, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); - closeReportSpam.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MessagesController.getInstance(currentAccount).hideReportSpam(dialog_id, currentUser, currentChat); - updateSpamView(); - } + closeReportSpam.setOnClickListener(v -> { + MessagesController.getInstance(currentAccount).hideReportSpam(dialog_id, currentUser, currentChat); + updateSpamView(); }); alertView = new FrameLayout(context); @@ -2765,18 +2697,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pagedownButton = new FrameLayout(context); pagedownButton.setVisibility(View.INVISIBLE); contentView.addView(pagedownButton, LayoutHelper.createFrame(66, 59, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, -3, 5)); - pagedownButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - wasManualScroll = true; - checkTextureViewPosition = true; - if (createUnreadMessageAfterId != 0) { - scrollToMessageId(createUnreadMessageAfterId, 0, false, returnToLoadIndex, false); - } else if (returnToMessageId > 0) { - scrollToMessageId(returnToMessageId, 0, true, returnToLoadIndex, false); - } else { - scrollToLastMessage(true); - } + pagedownButton.setOnClickListener(view -> { + wasManualScroll = true; + checkTextureViewPosition = true; + if (createUnreadMessageAfterId != 0) { + scrollToMessageId(createUnreadMessageAfterId, 0, false, returnToLoadIndex, false); + } else if (returnToMessageId > 0) { + scrollToMessageId(returnToMessageId, 0, true, returnToLoadIndex, false); + } else { + scrollToLastMessage(true); } }); @@ -2788,15 +2717,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void loadLastUnreadMention() { wasManualScroll = true; if (hasAllMentionsLocal) { - MessagesStorage.getInstance(currentAccount).getUnreadMention(dialog_id, new MessagesStorage.IntCallback() { - @Override - public void run(int param) { - if (param == 0) { - hasAllMentionsLocal = false; - loadLastUnreadMention(); - } else { - scrollToMessageId(param, 0, false, 0, false); - } + MessagesStorage.getInstance(currentAccount).getUnreadMention(dialog_id, param -> { + if (param == 0) { + hasAllMentionsLocal = false; + loadLastUnreadMention(); + } else { + scrollToMessageId(param, 0, false, 0, false); } }); } else { @@ -2805,45 +2731,37 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not req.peer = MessagesController.getInstance(currentAccount).getInputPeer((int) dialog_id); req.limit = 1; req.add_offset = newMentionsCount - 1; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - if (error != null || res.messages.isEmpty()) { - if (res != null) { - newMentionsCount = res.count; - } else { - newMentionsCount = 0; - } - messagesStorage.resetMentionsCount(dialog_id, newMentionsCount); - if (newMentionsCount == 0) { - hasAllMentionsLocal = true; - showMentiondownButton(false, true); - } else { - mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); - loadLastUnreadMention(); - } - } else { - int id = res.messages.get(0).id; - long mid = id; - if (ChatObject.isChannel(currentChat)) { - mid = mid | (((long) currentChat.id) << 32); - } - MessageObject object = messagesDict[0].get(id); - messagesStorage.markMessageAsMention(mid); - if (object != null) { - object.messageOwner.media_unread = true; - object.messageOwner.mentioned = true; - } - scrollToMessageId(id, 0, false, 0, false); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (error != null || res.messages.isEmpty()) { + if (res != null) { + newMentionsCount = res.count; + } else { + newMentionsCount = 0; + } + messagesStorage.resetMentionsCount(dialog_id, newMentionsCount); + if (newMentionsCount == 0) { + hasAllMentionsLocal = true; + showMentiondownButton(false, true); + } else { + mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); + loadLastUnreadMention(); + } + } else { + int id = res.messages.get(0).id; + long mid = id; + if (ChatObject.isChannel(currentChat)) { + mid = mid | (((long) currentChat.id) << 32); + } + MessageObject object = messagesDict[0].get(id); + messagesStorage.markMessageAsMention(mid); + if (object != null) { + object.messageOwner.media_unread = true; + object.messageOwner.mentioned = true; + } + scrollToMessageId(id, 0, false, 0, false); } - }); + })); } } @@ -2853,21 +2771,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - mentiondownButton.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - for (int a = 0; a < messages.size(); a++) { - MessageObject messageObject = messages.get(a); - if (messageObject.messageOwner.mentioned && !messageObject.isContentUnread()) { - messageObject.setContentIsRead(); - } + mentiondownButton.setOnLongClickListener(view -> { + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject.messageOwner.mentioned && !messageObject.isContentUnread()) { + messageObject.setContentIsRead(); } - newMentionsCount = 0; - MessagesController.getInstance(currentAccount).markMentionsAsRead(dialog_id); - hasAllMentionsLocal = true; - showMentiondownButton(false, true); - return true; } + newMentionsCount = 0; + MessagesController.getInstance(currentAccount).markMentionsAsRead(dialog_id); + hasAllMentionsLocal = true; + showMentiondownButton(false, true); + return true; }); if (!isBroadcast) { @@ -2983,12 +2898,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionListViewUpdateLayout(); } }; - mentionListView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return StickerPreviewViewer.getInstance().onTouch(event, mentionListView, 0, mentionsOnItemClickListener, null); - } - }); + mentionListView.setOnTouchListener((v, event) -> StickerPreviewViewer.getInstance().onTouch(event, mentionListView, 0, mentionsOnItemClickListener, null)); mentionListView.setTag(2); mentionLayoutManager = new LinearLayoutManager(context) { @Override @@ -3238,111 +3148,100 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionsAdapter.setNeedUsernames(currentChat != null); mentionsAdapter.setNeedBotContext(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); mentionsAdapter.setBotsCount(currentChat != null ? botsCount : 1); - mentionListView.setOnItemClickListener(mentionsOnItemClickListener = new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (mentionsAdapter.isBannedInline()) { - return; - } - Object object = mentionsAdapter.getItem(position); - int start = mentionsAdapter.getResultStartPosition(); - int len = mentionsAdapter.getResultLength(); - if (object instanceof TLRPC.User) { - if (searchingForUser && searchContainer.getVisibility() == View.VISIBLE) { - searchingUserMessages = (TLRPC.User) object; - if (searchingUserMessages == null) { - return; - } - String name = searchingUserMessages.first_name; - if (TextUtils.isEmpty(name)) { - name = searchingUserMessages.last_name; - } - searchingForUser = false; - String from = LocaleController.getString("SearchFrom", R.string.SearchFrom); - Spannable spannable = new SpannableString(from + " " + name); - spannable.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_actionBarDefaultSubtitle)), from.length() + 1, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - searchItem.setSearchFieldCaption(spannable); - mentionsAdapter.searchUsernameOrHashtag(null, 0, null, false); - searchItem.getSearchField().setHint(null); - searchItem.clearSearchText(); - DataQuery.getInstance(currentAccount).searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, searchingUserMessages); - } else { - TLRPC.User user = (TLRPC.User) object; - if (user != null) { - if (user.username != null) { - chatActivityEnterView.replaceWithText(start, len, "@" + user.username + " ", false); - } else { - String name = UserObject.getFirstName(user, false); - Spannable spannable = new SpannableString(name + " "); - spannable.setSpan(new URLSpanUserMention("" + user.id, 1), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - chatActivityEnterView.replaceWithText(start, len, spannable, false); - } - } - } - } else if (object instanceof String) { - if (mentionsAdapter.isBotCommands()) { - SendMessagesHelper.getInstance(currentAccount).sendMessage((String) object, dialog_id, replyingMessageObject, null, false, null, null, null); - chatActivityEnterView.setFieldText(""); - hideFieldPanel(); - } else { - chatActivityEnterView.replaceWithText(start, len, object + " ", false); - } - } else if (object instanceof TLRPC.BotInlineResult) { - if (chatActivityEnterView.getFieldText() == null) { + mentionListView.setOnItemClickListener(mentionsOnItemClickListener = (view, position) -> { + if (mentionsAdapter.isBannedInline()) { + return; + } + Object object = mentionsAdapter.getItem(position); + int start = mentionsAdapter.getResultStartPosition(); + int len = mentionsAdapter.getResultLength(); + if (object instanceof TLRPC.User) { + if (searchingForUser && searchContainer.getVisibility() == View.VISIBLE) { + searchingUserMessages = (TLRPC.User) object; + if (searchingUserMessages == null) { return; } - TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; - if ((result.type.equals("photo") && (result.photo != null || result.content != null) || - result.type.equals("gif") && (result.document != null || result.content != null) || - result.type.equals("video") && (result.document != null/* || result.content_url != null*/))) { - ArrayList arrayList = botContextResults = new ArrayList(mentionsAdapter.getSearchResultBotContext()); - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhotoForSelect(arrayList, mentionsAdapter.getItemPosition(position), 3, botContextProvider, null); - } else { - sendBotInlineResult(result); + String name = searchingUserMessages.first_name; + if (TextUtils.isEmpty(name)) { + name = searchingUserMessages.last_name; + } + searchingForUser = false; + String from = LocaleController.getString("SearchFrom", R.string.SearchFrom); + Spannable spannable = new SpannableString(from + " " + name); + spannable.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_actionBarDefaultSubtitle)), from.length() + 1, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + searchItem.setSearchFieldCaption(spannable); + mentionsAdapter.searchUsernameOrHashtag(null, 0, null, false); + searchItem.getSearchField().setHint(null); + searchItem.clearSearchText(); + DataQuery.getInstance(currentAccount).searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, searchingUserMessages); + } else { + TLRPC.User user = (TLRPC.User) object; + if (user != null) { + if (user.username != null) { + chatActivityEnterView.replaceWithText(start, len, "@" + user.username + " ", false); + } else { + String name = UserObject.getFirstName(user, false); + Spannable spannable = new SpannableString(name + " "); + spannable.setSpan(new URLSpanUserMention("" + user.id, 1), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + chatActivityEnterView.replaceWithText(start, len, spannable, false); + } } - } else if (object instanceof TLRPC.TL_inlineBotSwitchPM) { - processInlineBotContextPM((TLRPC.TL_inlineBotSwitchPM) object); - } else if (object instanceof EmojiSuggestion) { - String code = ((EmojiSuggestion) object).emoji; - chatActivityEnterView.addEmojiToRecent(code); - chatActivityEnterView.replaceWithText(start, len, code, true); } + } else if (object instanceof String) { + if (mentionsAdapter.isBotCommands()) { + SendMessagesHelper.getInstance(currentAccount).sendMessage((String) object, dialog_id, replyingMessageObject, null, false, null, null, null); + chatActivityEnterView.setFieldText(""); + hideFieldPanel(); + } else { + chatActivityEnterView.replaceWithText(start, len, object + " ", false); + } + } else if (object instanceof TLRPC.BotInlineResult) { + if (chatActivityEnterView.getFieldText() == null) { + return; + } + TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; + if ((result.type.equals("photo") && (result.photo != null || result.content != null) || + result.type.equals("gif") && (result.document != null || result.content != null) || + result.type.equals("video") && (result.document != null/* || result.content_url != null*/))) { + ArrayList arrayList = botContextResults = new ArrayList<>(mentionsAdapter.getSearchResultBotContext()); + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhotoForSelect(arrayList, mentionsAdapter.getItemPosition(position), 3, botContextProvider, null); + } else { + sendBotInlineResult(result); + } + } else if (object instanceof TLRPC.TL_inlineBotSwitchPM) { + processInlineBotContextPM((TLRPC.TL_inlineBotSwitchPM) object); + } else if (object instanceof EmojiSuggestion) { + String code = ((EmojiSuggestion) object).emoji; + chatActivityEnterView.addEmojiToRecent(code); + chatActivityEnterView.replaceWithText(start, len, code, true); } }); - mentionListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (getParentActivity() == null || !mentionsAdapter.isLongClickEnabled()) { - return false; - } - Object object = mentionsAdapter.getItem(position); - if (object instanceof String) { - if (mentionsAdapter.isBotCommands()) { - if (URLSpanBotCommand.enabled) { - chatActivityEnterView.setFieldText(""); - chatActivityEnterView.setCommand(null, (String) object, true, currentChat != null && currentChat.megagroup); - return true; - } - return false; - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); - builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mentionsAdapter.clearRecentHashtags(); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - return true; - } - } + mentionListView.setOnItemLongClickListener((view, position) -> { + if (getParentActivity() == null || !mentionsAdapter.isLongClickEnabled()) { return false; } + Object object = mentionsAdapter.getItem(position); + if (object instanceof String) { + if (mentionsAdapter.isBotCommands()) { + if (URLSpanBotCommand.enabled) { + chatActivityEnterView.setFieldText(""); + chatActivityEnterView.setCommand(null, (String) object, true, currentChat != null && currentChat.megagroup); + return true; + } + return false; + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), (dialogInterface, i) -> mentionsAdapter.clearRecentHashtags()); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + return true; + } + } + return false; }); mentionListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -3431,15 +3330,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.addView(actionBar); overlayView = new View(context); - overlayView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - checkRecordLocked(); - } - overlayView.getParent().requestDisallowInterceptTouchEvent(true); - return true; + overlayView.setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + checkRecordLocked(); } + overlayView.getParent().requestDisallowInterceptTouchEvent(true); + return true; }); contentView.addView(overlayView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); overlayView.setVisibility(View.GONE); @@ -3732,18 +3628,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; chatActivityEnterView.addTopView(replyLayout, 48); - replyLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (replyingMessageObject != null) { - scrollToMessageId(replyingMessageObject.getId(), 0, true, 0, false); - } else if (editingMessageObject != null && editingMessageObject.canEditMedia() && editingMessageObjectReqId == 0) { - if (chatAttachAlert == null) { - createChatAttachView(); - } - chatAttachAlert.setEditingMessageObject(editingMessageObject); - openAttachMenu(); + replyLayout.setOnClickListener(v -> { + if (replyingMessageObject != null) { + scrollToMessageId(replyingMessageObject.getId(), 0, true, 0, false); + } else if (editingMessageObject != null && editingMessageObject.canEditMedia() && editingMessageObjectReqId == 0) { + if (chatAttachAlert == null) { + createChatAttachView(); } + chatAttachAlert.setEditingMessageObject(editingMessageObject); + openAttachMenu(); } }); @@ -3761,14 +3654,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyCloseImageView.setImageResource(R.drawable.msg_panel_clear); replyCloseImageView.setScaleType(ImageView.ScaleType.CENTER); replyLayout.addView(replyCloseImageView, LayoutHelper.createFrame(52, 46, Gravity.RIGHT | Gravity.TOP, 0, 0.5f, 0, 0)); - replyCloseImageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (forwardingMessages != null) { - forwardingMessages.clear(); - } - showFieldPanel(false, null, null, null, foundWebPage, true); + replyCloseImageView.setOnClickListener(v -> { + if (forwardingMessages != null) { + forwardingMessages.clear(); } + showFieldPanel(false, null, null, null, foundWebPage, true); }); replyNameTextView = new SimpleTextView(context); @@ -3822,12 +3712,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; stickersListView.setTag(3); - stickersListView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return StickerPreviewViewer.getInstance().onTouch(event, stickersListView, 0, stickersOnItemClickListener, stickerPreviewViewerDelegate); - } - }); + stickersListView.setOnTouchListener((v, event) -> StickerPreviewViewer.getInstance().onTouch(event, stickersListView, 0, stickersOnItemClickListener, stickerPreviewViewerDelegate)); stickersListView.setDisallowInterceptTouchEvents(true); LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); @@ -3851,12 +3736,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not canvas.drawRect(0, bottom, getMeasuredWidth(), getMeasuredHeight(), Theme.chat_composeBackgroundPaint); } }; - searchContainer.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + searchContainer.setOnTouchListener((v, event) -> true); searchContainer.setWillNotDraw(false); searchContainer.setVisibility(View.INVISIBLE); searchContainer.setFocusable(true); @@ -3869,24 +3749,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchUpButton.setImageResource(R.drawable.search_up); searchUpButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_searchPanelIcons), PorterDuff.Mode.MULTIPLY)); searchContainer.addView(searchUpButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 48, 0)); - searchUpButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - DataQuery.getInstance(currentAccount).searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, searchingUserMessages); - } - }); + searchUpButton.setOnClickListener(view -> DataQuery.getInstance(currentAccount).searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, searchingUserMessages)); searchDownButton = new ImageView(context); searchDownButton.setScaleType(ImageView.ScaleType.CENTER); searchDownButton.setImageResource(R.drawable.search_down); searchDownButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_searchPanelIcons), PorterDuff.Mode.MULTIPLY)); searchContainer.addView(searchDownButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 0, 0)); - searchDownButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - DataQuery.getInstance(currentAccount).searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, searchingUserMessages); - } - }); + searchDownButton.setOnClickListener(view -> DataQuery.getInstance(currentAccount).searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, searchingUserMessages)); if (currentChat != null && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { searchUserButton = new ImageView(context); @@ -3894,20 +3764,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchUserButton.setImageResource(R.drawable.usersearch); searchUserButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_searchPanelIcons), PorterDuff.Mode.MULTIPLY)); searchContainer.addView(searchUserButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP, 48, 0, 0, 0)); - searchUserButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mentionLayoutManager.setReverseLayout(true); - mentionsAdapter.setSearchingMentions(true); - searchCalendarButton.setVisibility(View.GONE); - searchUserButton.setVisibility(View.GONE); - searchingForUser = true; - searchingUserMessages = null; - searchItem.getSearchField().setHint(LocaleController.getString("SearchMembers", R.string.SearchMembers)); - searchItem.setSearchFieldCaption(LocaleController.getString("SearchFrom", R.string.SearchFrom)); - AndroidUtilities.showKeyboard(searchItem.getSearchField()); - searchItem.clearSearchText(); - } + searchUserButton.setOnClickListener(view -> { + mentionLayoutManager.setReverseLayout(true); + mentionsAdapter.setSearchingMentions(true); + searchCalendarButton.setVisibility(View.GONE); + searchUserButton.setVisibility(View.GONE); + searchingForUser = true; + searchingUserMessages = null; + searchItem.getSearchField().setHint(LocaleController.getString("SearchMembers", R.string.SearchMembers)); + searchItem.setSearchFieldCaption(LocaleController.getString("SearchFrom", R.string.SearchFrom)); + AndroidUtilities.showKeyboard(searchItem.getSearchField()); + searchItem.clearSearchText(); }); } @@ -3916,58 +3783,46 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchCalendarButton.setImageResource(R.drawable.search_calendar); searchCalendarButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_searchPanelIcons), PorterDuff.Mode.MULTIPLY)); searchContainer.addView(searchCalendarButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - searchCalendarButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (getParentActivity() == null) { - return; - } - AndroidUtilities.hideKeyboard(searchItem.getSearchField()); - Calendar calendar = Calendar.getInstance(); - int year = calendar.get(Calendar.YEAR); - int monthOfYear = calendar.get(Calendar.MONTH); - int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); - try { - DatePickerDialog dialog = new DatePickerDialog(getParentActivity(), new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(year, month, dayOfMonth); - int date = (int) (calendar.getTime().getTime() / 1000); - clearChatData(); - waitingForLoad.add(lastLoadIndex); - MessagesController.getInstance(currentAccount).loadMessages(dialog_id, 30, 0, date, true, 0, classGuid, 4, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); - } - }, year, monthOfYear, dayOfMonth); - final DatePicker datePicker = dialog.getDatePicker(); - datePicker.setMinDate(1375315200000L); - datePicker.setMaxDate(System.currentTimeMillis()); - dialog.setButton(DialogInterface.BUTTON_POSITIVE, LocaleController.getString("JumpToDate", R.string.JumpToDate), dialog); - dialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { + searchCalendarButton.setOnClickListener(view -> { + if (getParentActivity() == null) { + return; + } + AndroidUtilities.hideKeyboard(searchItem.getSearchField()); + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + int monthOfYear = calendar.get(Calendar.MONTH); + int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); + try { + DatePickerDialog dialog = new DatePickerDialog(getParentActivity(), (view1, year1, month, dayOfMonth1) -> { + Calendar calendar1 = Calendar.getInstance(); + calendar1.clear(); + calendar1.set(year1, month, dayOfMonth1); + int date = (int) (calendar1.getTime().getTime() / 1000); + clearChatData(); + waitingForLoad.add(lastLoadIndex); + MessagesController.getInstance(currentAccount).loadMessages(dialog_id, 30, 0, date, true, 0, classGuid, 4, 0, ChatObject.isChannel(currentChat), lastLoadIndex++); + }, year, monthOfYear, dayOfMonth); + final DatePicker datePicker = dialog.getDatePicker(); + datePicker.setMinDate(1375315200000L); + datePicker.setMaxDate(System.currentTimeMillis()); + dialog.setButton(DialogInterface.BUTTON_POSITIVE, LocaleController.getString("JumpToDate", R.string.JumpToDate), dialog); + dialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog1, which) -> { + }); + if (Build.VERSION.SDK_INT >= 21) { + dialog.setOnShowListener(dialog12 -> { + int count = datePicker.getChildCount(); + for (int a = 0; a < count; a++) { + View child = datePicker.getChildAt(a); + ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); + layoutParams.width = LayoutHelper.MATCH_PARENT; + child.setLayoutParams(layoutParams); } }); - if (Build.VERSION.SDK_INT >= 21) { - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - int count = datePicker.getChildCount(); - for (int a = 0; a < count; a++) { - View child = datePicker.getChildAt(a); - ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - child.setLayoutParams(layoutParams); - } - } - }); - } - showDialog(dialog); - } catch (Exception e) { - FileLog.e(e); } + showDialog(dialog); + } catch (Exception e) { + FileLog.e(e); } }); @@ -4017,66 +3872,55 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bottomOverlayChat.setPadding(0, AndroidUtilities.dp(3), 0, 0); bottomOverlayChat.setVisibility(View.INVISIBLE); contentView.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); - bottomOverlayChat.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = null; - if (currentUser != null && userBlocked) { - if (currentUser.bot) { - String botUserLast = botUser; - botUser = null; - MessagesController.getInstance(currentAccount).unblockUser(currentUser.id); - if (botUserLast != null && botUserLast.length() != 0) { - MessagesController.getInstance(currentAccount).sendBotStart(currentUser, botUserLast); - } else { - SendMessagesHelper.getInstance(currentAccount).sendMessage("/start", dialog_id, null, null, false, null, null, null); - } - } else { - builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("AreYouSureUnblockContact", R.string.AreYouSureUnblockContact)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).unblockUser(currentUser.id); - } - }); - } - } else if (currentUser != null && currentUser.bot && botUser != null) { - if (botUser.length() != 0) { - MessagesController.getInstance(currentAccount).sendBotStart(currentUser, botUser); + bottomOverlayChat.setOnClickListener(view -> { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = null; + if (currentUser != null && userBlocked) { + if (currentUser.bot) { + String botUserLast = botUser; + botUser = null; + MessagesController.getInstance(currentAccount).unblockUser(currentUser.id); + if (botUserLast != null && botUserLast.length() != 0) { + MessagesController.getInstance(currentAccount).sendBotStart(currentUser, botUserLast); } else { SendMessagesHelper.getInstance(currentAccount).sendMessage("/start", dialog_id, null, null, false, null, null, null); } - botUser = null; - updateBottomOverlay(); } else { - if (ChatObject.isChannel(currentChat) && !(currentChat instanceof TLRPC.TL_channelForbidden)) { - if (ChatObject.isNotInChat(currentChat)) { - MessagesController.getInstance(currentAccount).addUserToChat(currentChat.id, UserConfig.getInstance(currentAccount).getCurrentUser(), null, 0, null, ChatActivity.this); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); - } else { - toggleMute(true); - } + builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("AreYouSureUnblockContact", R.string.AreYouSureUnblockContact)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).unblockUser(currentUser.id)); + } + } else if (currentUser != null && currentUser.bot && botUser != null) { + if (botUser.length() != 0) { + MessagesController.getInstance(currentAccount).sendBotStart(currentUser, botUser); + } else { + SendMessagesHelper.getInstance(currentAccount).sendMessage("/start", dialog_id, null, null, false, null, null, null); + } + botUser = null; + updateBottomOverlay(); + } else { + if (ChatObject.isChannel(currentChat) && !(currentChat instanceof TLRPC.TL_channelForbidden)) { + if (ChatObject.isNotInChat(currentChat)) { + MessagesController.getInstance(currentAccount).addUserToChat(currentChat.id, UserConfig.getInstance(currentAccount).getCurrentUser(), null, 0, null, ChatActivity.this); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); } else { - builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); - finishFragment(); - } - }); + toggleMute(true); } + } else { + builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + MessagesController.getInstance(currentAccount).deleteDialog(dialog_id, 0); + finishFragment(); + }); } - if (builder != null) { - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } + } + if (builder != null) { + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); } }); @@ -4471,66 +4315,60 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersAdapter.onDestroy(); } stickersListView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); - stickersListView.setAdapter(stickersAdapter = new StickersAdapter(getParentActivity(), new StickersAdapter.StickersAdapterDelegate() { - @Override - public void needChangePanelVisibility(final boolean show) { - if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { - return; - } - if (show) { - stickersListView.scrollToPosition(0); - stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); - } - if (runningAnimation != null) { - runningAnimation.cancel(); - runningAnimation = null; - } - if (stickersPanel.getVisibility() != View.INVISIBLE) { - runningAnimation = new AnimatorSet(); - runningAnimation.playTogether( - ObjectAnimator.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) - ); - runningAnimation.setDuration(150); - runningAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (runningAnimation != null && runningAnimation.equals(animation)) { - if (!show) { - stickersAdapter.clearStickers(); - stickersPanel.setVisibility(View.GONE); - if (StickerPreviewViewer.getInstance().isVisible()) { - StickerPreviewViewer.getInstance().close(); - } - StickerPreviewViewer.getInstance().reset(); + stickersListView.setAdapter(stickersAdapter = new StickersAdapter(getParentActivity(), show -> { + if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { + return; + } + if (show) { + stickersListView.scrollToPosition(0); + stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); + } + if (runningAnimation != null) { + runningAnimation.cancel(); + runningAnimation = null; + } + if (stickersPanel.getVisibility() != View.INVISIBLE) { + runningAnimation = new AnimatorSet(); + runningAnimation.playTogether( + ObjectAnimator.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) + ); + runningAnimation.setDuration(150); + runningAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + if (!show) { + stickersAdapter.clearStickers(); + stickersPanel.setVisibility(View.GONE); + if (StickerPreviewViewer.getInstance().isVisible()) { + StickerPreviewViewer.getInstance().close(); } - runningAnimation = null; + StickerPreviewViewer.getInstance().reset(); } + runningAnimation = null; } + } - @Override - public void onAnimationCancel(Animator animation) { - if (runningAnimation != null && runningAnimation.equals(animation)) { - runningAnimation = null; - } + @Override + public void onAnimationCancel(Animator animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + runningAnimation = null; } - }); - runningAnimation.start(); - } else if (!show) { - stickersPanel.setVisibility(View.GONE); - } + } + }); + runningAnimation.start(); + } else if (!show) { + stickersPanel.setVisibility(View.GONE); } })); - stickersListView.setOnItemClickListener(stickersOnItemClickListener = new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - TLRPC.Document document = stickersAdapter.getItem(position); - if (document instanceof TLRPC.TL_document) { - SendMessagesHelper.getInstance(currentAccount).sendSticker(document, dialog_id, replyingMessageObject); - hideFieldPanel(); - chatActivityEnterView.addStickerToRecent(document); - } - chatActivityEnterView.setFieldText(""); + stickersListView.setOnItemClickListener(stickersOnItemClickListener = (view, position) -> { + TLRPC.Document document = stickersAdapter.getItem(position); + if (document instanceof TLRPC.TL_document) { + SendMessagesHelper.getInstance(currentAccount).sendSticker(document, dialog_id, replyingMessageObject); + hideFieldPanel(); + chatActivityEnterView.addStickerToRecent(document); } + chatActivityEnterView.setFieldText(""); }); } @@ -4546,13 +4384,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { builder.setMessage(LocaleController.getString("AreYouSureShareMyContactInfo", R.string.AreYouSureShareMyContactInfo)); } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(UserConfig.getInstance(currentAccount).getCurrentUser(), dialog_id, messageObject, null, null); - moveScrollToLastMessage(); - hideFieldPanel(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + SendMessagesHelper.getInstance(currentAccount).sendMessage(UserConfig.getInstance(currentAccount).getCurrentUser(), dialog_id, messageObject, null, null); + moveScrollToLastMessage(); + hideFieldPanel(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -4625,12 +4460,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not voiceHintAnimation = null; } else { AndroidUtilities.cancelRunOnUIThread(voiceHintHideRunnable); - AndroidUtilities.runOnUIThread(voiceHintHideRunnable = new Runnable() { - @Override - public void run() { - hideVoiceHint(); - } - }, 2000); + AndroidUtilities.runOnUIThread(voiceHintHideRunnable = this::hideVoiceHint, 2000); return; } } else if (voiceHintAnimation != null) { @@ -4647,12 +4477,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void onAnimationEnd(Animator animation) { if (animation.equals(voiceHintAnimation)) { voiceHintAnimation = null; - AndroidUtilities.runOnUIThread(voiceHintHideRunnable = new Runnable() { - @Override - public void run() { - hideVoiceHint(); - } - }, 2000); + AndroidUtilities.runOnUIThread(voiceHintHideRunnable = () -> hideVoiceHint(), 2000); } } @@ -4700,27 +4525,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (mediaBanTooltip == null) { - return; - } - AnimatorSet AnimatorSet = new AnimatorSet(); - AnimatorSet.playTogether( - ObjectAnimator.ofFloat(mediaBanTooltip, "alpha", 0.0f) - ); - AnimatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (mediaBanTooltip != null) { - mediaBanTooltip.setVisibility(View.GONE); - } - } - }); - AnimatorSet.setDuration(300); - AnimatorSet.start(); + AndroidUtilities.runOnUIThread(() -> { + if (mediaBanTooltip == null) { + return; } + AnimatorSet AnimatorSet = new AnimatorSet(); + AnimatorSet.playTogether( + ObjectAnimator.ofFloat(mediaBanTooltip, "alpha", 0.0f) + ); + AnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mediaBanTooltip != null) { + mediaBanTooltip.setVisibility(View.GONE); + } + } + }); + AnimatorSet.setDuration(300); + AnimatorSet.start(); }, 5000); } }); @@ -4771,27 +4593,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (gifHintTextView == null) { - return; - } - AnimatorSet AnimatorSet = new AnimatorSet(); - AnimatorSet.playTogether( - ObjectAnimator.ofFloat(gifHintTextView, "alpha", 0.0f) - ); - AnimatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (gifHintTextView != null) { - gifHintTextView.setVisibility(View.GONE); - } - } - }); - AnimatorSet.setDuration(300); - AnimatorSet.start(); + AndroidUtilities.runOnUIThread(() -> { + if (gifHintTextView == null) { + return; } + AnimatorSet AnimatorSet = new AnimatorSet(); + AnimatorSet.playTogether( + ObjectAnimator.ofFloat(gifHintTextView, "alpha", 0.0f) + ); + AnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (gifHintTextView != null) { + gifHintTextView.setVisibility(View.GONE); + } + } + }); + AnimatorSet.setDuration(300); + AnimatorSet.start(); }, 2000); } }); @@ -5093,14 +4912,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } AudioSelectActivity fragment = new AudioSelectActivity(); - fragment.setDelegate(new AudioSelectActivity.AudioSelectActivityDelegate() { - @Override - public void didSelectAudio(ArrayList audios) { - fillEditingMediaWithCaption(null, null); - SendMessagesHelper.prepareSendingAudioDocuments(audios, dialog_id, replyingMessageObject, editingMessageObject); - hideFieldPanel(); - DataQuery.getInstance(currentAccount).cleanDraft(dialog_id, true); - } + fragment.setDelegate(audios -> { + fillEditingMediaWithCaption(null, null); + SendMessagesHelper.prepareSendingAudioDocuments(audios, dialog_id, replyingMessageObject, editingMessageObject); + hideFieldPanel(); + DataQuery.getInstance(currentAccount).cleanDraft(dialog_id, true); }); presentFragment(fragment); } else if (which == attach_contact) { @@ -5111,13 +4927,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } PhonebookSelectActivity activity = new PhonebookSelectActivity(); - activity.setDelegate(new PhonebookSelectActivity.PhonebookSelectActivityDelegate() { - @Override - public void didSelectContact(TLRPC.User user) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(user, dialog_id, replyingMessageObject, null, null); - hideFieldPanel(); - DataQuery.getInstance(currentAccount).cleanDraft(dialog_id, true); - } + activity.setDelegate(user -> { + SendMessagesHelper.getInstance(currentAccount).sendMessage(user, dialog_id, replyingMessageObject, null, null); + hideFieldPanel(); + DataQuery.getInstance(currentAccount).cleanDraft(dialog_id, true); }); presentFragment(activity); } @@ -5156,151 +4969,129 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showFieldPanelForWebPage(false, foundWebPage, false); } final MessagesController messagesController = MessagesController.getInstance(currentAccount); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (linkSearchRequestId != 0) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(linkSearchRequestId, true); - linkSearchRequestId = 0; - } - ArrayList urls = null; - CharSequence textToCheck; - try { - Matcher m = AndroidUtilities.WEB_URL.matcher(charSequence); - while (m.find()) { - if (m.start() > 0) { - if (charSequence.charAt(m.start() - 1) == '@') { - continue; - } + Utilities.searchQueue.postRunnable(() -> { + if (linkSearchRequestId != 0) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(linkSearchRequestId, true); + linkSearchRequestId = 0; + } + ArrayList urls = null; + CharSequence textToCheck; + try { + Matcher m = AndroidUtilities.WEB_URL.matcher(charSequence); + while (m.find()) { + if (m.start() > 0) { + if (charSequence.charAt(m.start() - 1) == '@') { + continue; } + } + if (urls == null) { + urls = new ArrayList<>(); + } + urls.add(charSequence.subSequence(m.start(), m.end())); + } + if (charSequence instanceof Spannable) { + URLSpanReplacement[] spans = ((Spannable) charSequence).getSpans(0, charSequence.length(), URLSpanReplacement.class); + if (spans != null && spans.length > 0) { if (urls == null) { urls = new ArrayList<>(); } - urls.add(charSequence.subSequence(m.start(), m.end())); - } - if (charSequence instanceof Spannable) { - URLSpanReplacement[] spans = ((Spannable) charSequence).getSpans(0, charSequence.length(), URLSpanReplacement.class); - if (spans != null && spans.length > 0) { - if (urls == null) { - urls = new ArrayList<>(); - } - for (int a = 0; a < spans.length; a++) { - urls.add(spans[a].getURL()); - } + for (int a = 0; a < spans.length; a++) { + urls.add(spans[a].getURL()); } } - if (urls != null && foundUrls != null && urls.size() == foundUrls.size()) { - boolean clear = true; - for (int a = 0; a < urls.size(); a++) { - if (!TextUtils.equals(urls.get(a), foundUrls.get(a))) { - clear = false; - } - } - if (clear) { - return; - } - } - foundUrls = urls; - if (urls == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (foundWebPage != null) { - showFieldPanelForWebPage(false, foundWebPage, false); - foundWebPage = null; - } - } - }); - return; - } - textToCheck = TextUtils.join(" ", urls); - } catch (Exception e) { - FileLog.e(e); - String text = charSequence.toString().toLowerCase(); - if (charSequence.length() < 13 || !text.contains("http://") && !text.contains("https://")) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (foundWebPage != null) { - showFieldPanelForWebPage(false, foundWebPage, false); - foundWebPage = null; - } - } - }); - return; - } - textToCheck = charSequence; } - - if (currentEncryptedChat != null && messagesController.secretWebpagePreview == 2) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - messagesController.secretWebpagePreview = 1; - MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", MessagesController.getInstance(currentAccount).secretWebpagePreview).commit(); - foundUrls = null; - searchLinks(charSequence, force); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setMessage(LocaleController.getString("SecretLinkPreviewAlert", R.string.SecretLinkPreviewAlert)); - showDialog(builder.create()); - - messagesController.secretWebpagePreview = 0; - MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", messagesController.secretWebpagePreview).commit(); + if (urls != null && foundUrls != null && urls.size() == foundUrls.size()) { + boolean clear = true; + for (int a = 0; a < urls.size(); a++) { + if (!TextUtils.equals(urls.get(a), foundUrls.get(a))) { + clear = false; + } + } + if (clear) { + return; + } + } + foundUrls = urls; + if (urls == null) { + AndroidUtilities.runOnUIThread(() -> { + if (foundWebPage != null) { + showFieldPanelForWebPage(false, foundWebPage, false); + foundWebPage = null; } }); return; } - - final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); - if (textToCheck instanceof String) { - req.message = (String) textToCheck; - } else { - req.message = textToCheck.toString(); + textToCheck = TextUtils.join(" ", urls); + } catch (Exception e) { + FileLog.e(e); + String text = charSequence.toString().toLowerCase(); + if (charSequence.length() < 13 || !text.contains("http://") && !text.contains("https://")) { + AndroidUtilities.runOnUIThread(() -> { + if (foundWebPage != null) { + showFieldPanelForWebPage(false, foundWebPage, false); + foundWebPage = null; + } + }); + return; } - linkSearchRequestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - linkSearchRequestId = 0; - if (error == null) { - if (response instanceof TLRPC.TL_messageMediaWebPage) { - foundWebPage = ((TLRPC.TL_messageMediaWebPage) response).webpage; - if (foundWebPage instanceof TLRPC.TL_webPage || foundWebPage instanceof TLRPC.TL_webPagePending) { - if (foundWebPage instanceof TLRPC.TL_webPagePending) { - pendingLinkSearchString = req.message; - } - if (currentEncryptedChat != null && foundWebPage instanceof TLRPC.TL_webPagePending) { - foundWebPage.url = req.message; - } - showFieldPanelForWebPage(true, foundWebPage, false); - } else { - if (foundWebPage != null) { - showFieldPanelForWebPage(false, foundWebPage, false); - foundWebPage = null; - } - } - } else { - if (foundWebPage != null) { - showFieldPanelForWebPage(false, foundWebPage, false); - foundWebPage = null; - } - } - } - } - }); - } - }); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(linkSearchRequestId, classGuid); + textToCheck = charSequence; } + + if (currentEncryptedChat != null && messagesController.secretWebpagePreview == 2) { + AndroidUtilities.runOnUIThread(() -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + messagesController.secretWebpagePreview = 1; + MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", MessagesController.getInstance(currentAccount).secretWebpagePreview).commit(); + foundUrls = null; + searchLinks(charSequence, force); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setMessage(LocaleController.getString("SecretLinkPreviewAlert", R.string.SecretLinkPreviewAlert)); + showDialog(builder.create()); + + messagesController.secretWebpagePreview = 0; + MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", messagesController.secretWebpagePreview).commit(); + }); + return; + } + + final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); + if (textToCheck instanceof String) { + req.message = (String) textToCheck; + } else { + req.message = textToCheck.toString(); + } + linkSearchRequestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + linkSearchRequestId = 0; + if (error == null) { + if (response instanceof TLRPC.TL_messageMediaWebPage) { + foundWebPage = ((TLRPC.TL_messageMediaWebPage) response).webpage; + if (foundWebPage instanceof TLRPC.TL_webPage || foundWebPage instanceof TLRPC.TL_webPagePending) { + if (foundWebPage instanceof TLRPC.TL_webPagePending) { + pendingLinkSearchString = req.message; + } + if (currentEncryptedChat != null && foundWebPage instanceof TLRPC.TL_webPagePending) { + foundWebPage.url = req.message; + } + showFieldPanelForWebPage(true, foundWebPage, false); + } else { + if (foundWebPage != null) { + showFieldPanelForWebPage(false, foundWebPage, false); + foundWebPage = null; + } + } + } else { + if (foundWebPage != null) { + showFieldPanelForWebPage(false, foundWebPage, false); + foundWebPage = null; + } + } + } + })); + + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(linkSearchRequestId, classGuid); }); } @@ -5368,12 +5159,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (searchItem != null && actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(false); chatActivityEnterView.setFieldFocused(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (chatActivityEnterView != null) { - chatActivityEnterView.openKeyboard(); - } + AndroidUtilities.runOnUIThread(() -> { + if (chatActivityEnterView != null) { + chatActivityEnterView.openKeyboard(); } }, 100); } @@ -5661,9 +5449,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (forwardingMessages != null) { forwardMessages(forwardingMessages, false); } - if (editingMessageObject != null) { - //TODO ? - } chatActivityEnterView.setForceShowSendButton(false, false); chatActivityEnterView.hideTopView(false); chatActivityEnterView.setReplyingMessageObject(null); @@ -5950,12 +5735,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (inLayout) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - inlineUpdate1(); - } - }); + AndroidUtilities.runOnUIThread(this::inlineUpdate1); } else { inlineUpdate1(); } @@ -5964,12 +5744,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (!firstUnreadSent) { newUnreadMessageCount = 0; if (inLayout) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - inlineUpdate2(); - } - }); + AndroidUtilities.runOnUIThread(this::inlineUpdate2); } else { inlineUpdate2(); } @@ -6355,17 +6130,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("PermissionNoAudioVideo", R.string.PermissionNoAudioVideo)); - builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { - @TargetApi(Build.VERSION_CODES.GINGERBREAD) - @Override - public void onClick(DialogInterface dialog, int which) { - try { - Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e(e); - } + builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e(e); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); @@ -7095,7 +6866,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - boolean wasUnread = false; int unread_to_load = 0; if (fnid != 0) { last_message_id = (Integer) args[5]; @@ -7149,12 +6919,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } firstLoading = false; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (parentLayout != null) { - parentLayout.resumeDelayedFragmentAnimation(); - } + AndroidUtilities.runOnUIThread(() -> { + if (parentLayout != null) { + parentLayout.resumeDelayedFragmentAnimation(); } }); } @@ -7228,9 +6995,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not needAnimateToMessage = null; } - if (!obj.isOut() && obj.isUnread()) { - wasUnread = true; - } messagesDict[loadIndex].put(obj.getId(), obj); ArrayList dayArray = messagesByDays.get(obj.dateKey); @@ -7416,12 +7180,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (newRowsCount > 0) { int firstVisPos = chatLayoutManager.findFirstVisibleItemPosition(); - int top = 0; if (firstVisPos == 0) { firstVisPos++; } View firstVisView = chatLayoutManager.findViewByPosition(firstVisPos); - top = ((firstVisView == null) ? 0 : chatListView.getMeasuredHeight() - firstVisView.getBottom() - chatListView.getPaddingBottom()); + int top = ((firstVisView == null) ? 0 : chatListView.getMeasuredHeight() - firstVisView.getBottom() - chatListView.getPaddingBottom()); chatAdapter.notifyItemRangeInserted(1, newRowsCount); if (firstVisPos != RecyclerView.NO_POSITION) { chatLayoutManager.scrollToPositionWithOffset(firstVisPos + newRowsCount - rowsRemoved, top); @@ -7713,22 +7476,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bundle.putInt("chat_id", obj.messageOwner.action.channel_id); final BaseFragment lastFragment = parentLayout.fragmentsStack.size() > 0 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) : null; final int channel_id = obj.messageOwner.action.channel_id; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - ActionBarLayout parentLayout = ChatActivity.this.parentLayout; - if (lastFragment != null) { - NotificationCenter.getInstance(currentAccount).removeObserver(lastFragment, NotificationCenter.closeChats); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - parentLayout.presentFragment(new ChatActivity(bundle), true); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).loadFullChat(channel_id, 0, true); - } - }, 1000); + AndroidUtilities.runOnUIThread(() -> { + ActionBarLayout parentLayout = ChatActivity.this.parentLayout; + if (lastFragment != null) { + NotificationCenter.getInstance(currentAccount).removeObserver(lastFragment, NotificationCenter.closeChats); } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + parentLayout.presentFragment(new ChatActivity(bundle), true); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).loadFullChat(channel_id, 0, true), 1000); }); return; } else if (currentChat != null && currentChat.megagroup && (obj.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser || obj.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser)) { @@ -7876,22 +7631,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bundle.putInt("chat_id", obj.messageOwner.action.channel_id); final BaseFragment lastFragment = parentLayout.fragmentsStack.size() > 0 ? parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) : null; final int channel_id = obj.messageOwner.action.channel_id; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - ActionBarLayout parentLayout = ChatActivity.this.parentLayout; - if (lastFragment != null) { - NotificationCenter.getInstance(currentAccount).removeObserver(lastFragment, NotificationCenter.closeChats); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - parentLayout.presentFragment(new ChatActivity(bundle), true); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).loadFullChat(channel_id, 0, true); - } - }, 1000); + AndroidUtilities.runOnUIThread(() -> { + ActionBarLayout parentLayout = ChatActivity.this.parentLayout; + if (lastFragment != null) { + NotificationCenter.getInstance(currentAccount).removeObserver(lastFragment, NotificationCenter.closeChats); } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + parentLayout.presentFragment(new ChatActivity(bundle), true); + AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).loadFullChat(channel_id, 0, true), 1000); }); if (newGroups != null) { for (int b = 0; b < newGroups.size(); b++) { @@ -8013,7 +7760,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (lastVisible == RecyclerView.NO_POSITION) { lastVisible = 0; } - if (lastVisible == 0 || hasFromMe) { + View child = chatLayoutManager.findViewByPosition(lastVisible); + int diff; + if (child != null) { + diff = child.getBottom() - chatListView.getMeasuredHeight(); + } else { + diff = 0; + } + if (lastVisible == 0 && diff <= AndroidUtilities.dp(5) || hasFromMe) { newUnreadMessageCount = 0; if (!firstLoading) { if (paused) { @@ -8684,7 +8438,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (id == NotificationCenter.blockedUsersDidLoaded) { if (currentUser != null) { boolean oldValue = userBlocked; - userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.contains(currentUser.id); + userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.indexOfKey(currentUser.id) >= 0; if (oldValue != userBlocked) { updateBottomOverlay(); } @@ -8888,7 +8642,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } int loadIndex = did == dialog_id ? 0 : 1; - boolean changed = false; ArrayList messageObjects = (ArrayList) args[1]; LongSparseArray newGroups = null; for (int a = 0; a < messageObjects.size(); a++) { @@ -8909,9 +8662,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (!old.isEditing()) { - messageObject.messageOwner.attachPath = old.messageOwner.attachPath; - messageObject.attachPathExists = old.attachPathExists; - messageObject.mediaExists = old.mediaExists; + if (old.getFileName().equals(messageObject.getFileName())) { + messageObject.messageOwner.attachPath = old.messageOwner.attachPath; + messageObject.attachPathExists = old.attachPathExists; + messageObject.mediaExists = old.mediaExists; + } else { + messageObject.checkMediaExistance(); + } } messagesDict[loadIndex].put(old.getId(), messageObject); } else { @@ -8985,7 +8742,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - changed = true; } } } @@ -9227,19 +8983,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } locationAlertShown = true; - AlertsCreator.showSecretLocationAlert(getParentActivity(), currentAccount, new Runnable() { - @Override - public void run() { - int count = chatListView.getChildCount(); - for (int a = 0; a < count; a++) { - View view = chatListView.getChildAt(a); - MessageObject message = null; - if (view instanceof ChatMessageCell) { - ChatMessageCell cell = (ChatMessageCell) view; - message = cell.getMessageObject(); - if (message.type == 4) { - cell.forceResetMessageObject(); - } + AlertsCreator.showSecretLocationAlert(getParentActivity(), currentAccount, () -> { + int count = chatListView.getChildCount(); + for (int a = 0; a < count; a++) { + View view = chatListView.getChildAt(a); + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; + MessageObject message = cell.getMessageObject(); + if (message.type == 4) { + cell.forceResetMessageObject(); } } } @@ -9457,12 +9209,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setVisibility(View.VISIBLE); bottomOverlayChat.setVisibility(View.INVISIBLE); chatActivityEnterView.setFieldFocused(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - chatActivityEnterView.openKeyboard(); - } - }, 100); + AndroidUtilities.runOnUIThread(() -> chatActivityEnterView.openKeyboard(), 100); } else { bottomOverlayChat.setVisibility(View.VISIBLE); chatActivityEnterView.setFieldFocused(false); @@ -9876,12 +9623,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkListViewPaddingsInternal(); - } - }); + AndroidUtilities.runOnUIThread(this::checkListViewPaddingsInternal); } } @@ -10043,12 +9785,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (startVideoEdit != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - openVideoEditor(startVideoEdit, null); - startVideoEdit = null; - } + AndroidUtilities.runOnUIThread(() -> { + openVideoEditor(startVideoEdit, null); + startVideoEdit = null; }); } @@ -10178,7 +9917,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not CharSequence message; if (!draftMessage.entities.isEmpty()) { SpannableStringBuilder stringBuilder = SpannableStringBuilder.valueOf(draftMessage.message); - DataQuery.getInstance(currentAccount).sortEntities(draftMessage.entities); + DataQuery.sortEntities(draftMessage.entities); int addToOffset = 0; for (int a = 0; a < draftMessage.entities.size(); a++) { TLRPC.MessageEntity entity = draftMessage.entities.get(a); @@ -10216,13 +9955,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setFieldText(message); if (getArguments().getBoolean("hasUrl", false)) { chatActivityEnterView.setSelection(draftMessage.message.indexOf('\n') + 1); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (chatActivityEnterView != null) { - chatActivityEnterView.setFieldFocused(true); - chatActivityEnterView.openKeyboard(); - } + AndroidUtilities.runOnUIThread(() -> { + if (chatActivityEnterView != null) { + chatActivityEnterView.setFieldFocused(true); + chatActivityEnterView.openKeyboard(); } }, 700); } @@ -10433,54 +10169,40 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); req.channel = MessagesController.getInputChannel(currentChat); req.user_id = MessagesController.getInstance(currentAccount).getInputUser(user); - int requestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog[0].dismiss(); - } catch (Throwable ignore) { + int requestId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog[0].dismiss(); + } catch (Throwable ignore) { - } - progressDialog[0] = null; - int loadType = 2; - if (response != null) { - TLRPC.TL_channels_channelParticipant participant = (TLRPC.TL_channels_channelParticipant) response; - if (!(participant.participant instanceof TLRPC.TL_channelParticipantAdmin || participant.participant instanceof TLRPC.TL_channelParticipantCreator)) { - loadType = 0; - } - } - createDeleteMessagesAlert(finalSelectedObject, finalSelectedGroup, loadType); - } - }); } - }); + progressDialog[0] = null; + int loadType = 2; + if (response != null) { + TLRPC.TL_channels_channelParticipant participant = (TLRPC.TL_channels_channelParticipant) response; + if (!(participant.participant instanceof TLRPC.TL_channelParticipantAdmin || participant.participant instanceof TLRPC.TL_channelParticipantCreator)) { + loadType = 0; + } + } + createDeleteMessagesAlert(finalSelectedObject, finalSelectedGroup, loadType); + })); if (requestId != 0) { final int reqId = requestId; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (progressDialog[0] == null) { - return; - } - progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog[0].setCanceledOnTouchOutside(false); - progressDialog[0].setCancelable(false); - progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - showDialog(progressDialog[0]); + AndroidUtilities.runOnUIThread(() -> { + if (progressDialog[0] == null) { + return; } + progressDialog[0].setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog[0].setCanceledOnTouchOutside(false); + progressDialog[0].setCancelable(false); + progressDialog[0].setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + }); + showDialog(progressDialog[0]); }, 1000); } return; @@ -10503,17 +10225,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 48 * num, 0, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!v.isEnabled()) { - return; - } - CheckBoxCell cell = (CheckBoxCell) v; - Integer num = (Integer) cell.getTag(); - checks[num] = !checks[num]; - cell.setChecked(checks[num], true); + cell.setOnClickListener(v -> { + if (!v.isEnabled()) { + return; } + CheckBoxCell cell13 = (CheckBoxCell) v; + Integer num1 = (Integer) cell13.getTag(); + checks[num1] = !checks[num1]; + cell13.setChecked(checks[num1], true); }); num++; } @@ -10529,13 +10248,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - deleteForAll[0] = !deleteForAll[0]; - cell.setChecked(deleteForAll[0], true); - } + cell.setOnClickListener(v -> { + CheckBoxCell cell12 = (CheckBoxCell) v; + deleteForAll[0] = !deleteForAll[0]; + cell12.setChecked(deleteForAll[0], true); }); builder.setView(frameLayout); } else { @@ -10583,91 +10299,82 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - deleteForAll[0] = !deleteForAll[0]; - cell.setChecked(deleteForAll[0], true); - } + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + deleteForAll[0] = !deleteForAll[0]; + cell1.setChecked(deleteForAll[0], true); }); builder.setView(frameLayout); } } final TLRPC.User userFinal = user; - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ArrayList ids = null; - if (finalSelectedObject != null) { - ids = new ArrayList<>(); - ArrayList random_ids = null; - if (finalSelectedGroup != null) { - for (int a = 0; a < finalSelectedGroup.messages.size(); a++) { - MessageObject messageObject = finalSelectedGroup.messages.get(a); - ids.add(messageObject.getId()); - if (currentEncryptedChat != null && messageObject.messageOwner.random_id != 0 && messageObject.type != 10) { - if (random_ids == null) { - random_ids = new ArrayList<>(); - } - random_ids.add(messageObject.messageOwner.random_id); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + ArrayList ids = null; + if (finalSelectedObject != null) { + ids = new ArrayList<>(); + ArrayList random_ids = null; + if (finalSelectedGroup != null) { + for (int a = 0; a < finalSelectedGroup.messages.size(); a++) { + MessageObject messageObject = finalSelectedGroup.messages.get(a); + ids.add(messageObject.getId()); + if (currentEncryptedChat != null && messageObject.messageOwner.random_id != 0 && messageObject.type != 10) { + if (random_ids == null) { + random_ids = new ArrayList<>(); } - } - } else { - ids.add(finalSelectedObject.getId()); - if (currentEncryptedChat != null && finalSelectedObject.messageOwner.random_id != 0 && finalSelectedObject.type != 10) { - random_ids = new ArrayList<>(); - random_ids.add(finalSelectedObject.messageOwner.random_id); + random_ids.add(messageObject.messageOwner.random_id); } } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, finalSelectedObject.messageOwner.to_id.channel_id, deleteForAll[0]); } else { - for (int a = 1; a >= 0; a--) { - ids = new ArrayList<>(); - for (int b = 0; b < selectedMessagesIds[a].size(); b++) { - ids.add(selectedMessagesIds[a].keyAt(b)); - } - ArrayList random_ids = null; - int channelId = 0; - if (!ids.isEmpty()) { - MessageObject msg = selectedMessagesIds[a].get(ids.get(0)); - if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { - channelId = msg.messageOwner.to_id.channel_id; - } - } - if (currentEncryptedChat != null) { - random_ids = new ArrayList<>(); - for (int b = 0; b < selectedMessagesIds[a].size(); b++) { - MessageObject msg = selectedMessagesIds[a].valueAt(b); - if (msg.messageOwner.random_id != 0 && msg.type != 10) { - random_ids.add(msg.messageOwner.random_id); - } - } - } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, channelId, deleteForAll[0]); + ids.add(finalSelectedObject.getId()); + if (currentEncryptedChat != null && finalSelectedObject.messageOwner.random_id != 0 && finalSelectedObject.type != 10) { + random_ids = new ArrayList<>(); + random_ids.add(finalSelectedObject.messageOwner.random_id); } - actionBar.hideActionMode(); - updatePinnedMessageView(true); } - if (userFinal != null) { - if (checks[0]) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(currentChat.id, userFinal, info); + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, finalSelectedObject.messageOwner.to_id.channel_id, deleteForAll[0]); + } else { + for (int a = 1; a >= 0; a--) { + ids = new ArrayList<>(); + for (int b = 0; b < selectedMessagesIds[a].size(); b++) { + ids.add(selectedMessagesIds[a].keyAt(b)); } - if (checks[1]) { - TLRPC.TL_channels_reportSpam req = new TLRPC.TL_channels_reportSpam(); - req.channel = MessagesController.getInputChannel(currentChat); - req.user_id = MessagesController.getInstance(currentAccount).getInputUser(userFinal); - req.id = ids; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - + ArrayList random_ids = null; + int channelId = 0; + if (!ids.isEmpty()) { + MessageObject msg = selectedMessagesIds[a].get(ids.get(0)); + if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { + channelId = msg.messageOwner.to_id.channel_id; + } + } + if (currentEncryptedChat != null) { + random_ids = new ArrayList<>(); + for (int b = 0; b < selectedMessagesIds[a].size(); b++) { + MessageObject msg = selectedMessagesIds[a].valueAt(b); + if (msg.messageOwner.random_id != 0 && msg.type != 10) { + random_ids.add(msg.messageOwner.random_id); } - }); - } - if (checks[2]) { - MessagesController.getInstance(currentAccount).deleteUserChannelHistory(currentChat, userFinal, 0); + } } + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, channelId, deleteForAll[0]); + } + actionBar.hideActionMode(); + updatePinnedMessageView(true); + } + if (userFinal != null) { + if (checks[0]) { + MessagesController.getInstance(currentAccount).deleteUserFromChat(currentChat.id, userFinal, info); + } + if (checks[1]) { + TLRPC.TL_channels_reportSpam req = new TLRPC.TL_channels_reportSpam(); + req.channel = MessagesController.getInputChannel(currentChat); + req.user_id = MessagesController.getInstance(currentAccount).getInputUser(userFinal); + req.id = ids; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }); + } + if (checks[2]) { + MessagesController.getInstance(currentAccount).deleteUserChannelHistory(currentChat, userFinal, 0); } } }); @@ -10996,14 +10703,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); final CharSequence[] finalItems = items.toArray(new CharSequence[items.size()]); - builder.setItems(finalItems, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (selectedObject == null || i < 0 || i >= options.size()) { - return; - } - processSelectedOption(options.get(i)); + builder.setItems(finalItems, (dialogInterface, i) -> { + if (selectedObject == null || i < 0 || i >= options.size()) { + return; } + processSelectedOption(options.get(i)); }); builder.setTitle(LocaleController.getString("Message", R.string.Message)); @@ -11069,33 +10773,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.TL_messages_getMessageEditData req = new TLRPC.TL_messages_getMessageEditData(); req.peer = MessagesController.getInstance(currentAccount).getInputPeer((int) dialog_id); req.id = messageObject.getId(); - editingMessageObjectReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - editingMessageObjectReqId = 0; - if (response == null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showDialog(builder.create()); + editingMessageObjectReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + editingMessageObjectReqId = 0; + if (response == null) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); - if (chatActivityEnterView != null) { - chatActivityEnterView.setEditingMessageObject(null, false); - hideFieldPanel(); - } - } else { - if (chatActivityEnterView != null) { - chatActivityEnterView.showEditDoneProgress(false, true); - } - } - } - }); + if (chatActivityEnterView != null) { + chatActivityEnterView.setEditingMessageObject(null, false); + hideFieldPanel(); + } + } else { + if (chatActivityEnterView != null) { + chatActivityEnterView.showEditDoneProgress(false, true); + } } - }); + })); } private String getMessageContent(MessageObject messageObject, int previousUid, boolean name) { @@ -11379,25 +11075,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cell.setText(LocaleController.getString("PinNotify", R.string.PinNotify), "", true, false); cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 0, 8, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - checks[0] = !checks[0]; - cell.setChecked(checks[0], true); - } + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + checks[0] = !checks[0]; + cell1.setChecked(checks[0], true); }); builder.setView(frameLayout); } else { builder.setMessage(LocaleController.getString("PinMessageAlertChannel", R.string.PinMessageAlertChannel)); checks = new boolean[]{false}; } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, mid, checks[0]); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, mid, checks[0])); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -11406,12 +11094,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not case 14: { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, 0, false); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).pinChannelMessage(currentChat, 0, false)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -11465,28 +11148,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.TL_channels_exportMessageLink req = new TLRPC.TL_channels_exportMessageLink(); req.id = selectedObject.getId(); req.channel = MessagesController.getInputChannel(currentChat); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - TLRPC.TL_exportedMessageLink exportedMessageLink = (TLRPC.TL_exportedMessageLink) response; - try { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", exportedMessageLink.link); - clipboard.setPrimaryClip(clip); - Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } - } - - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + TLRPC.TL_exportedMessageLink exportedMessageLink = (TLRPC.TL_exportedMessageLink) response; + try { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("label", exportedMessageLink.link); + clipboard.setPrimaryClip(clip); + Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); + } } - }); + + })); break; } case 23: { @@ -11608,12 +11283,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setTitle(LocaleController.getString("DiscardVoiceMessageTitle", R.string.DiscardVoiceMessageTitle)); builder.setMessage(LocaleController.getString("DiscardVoiceMessageDescription", R.string.DiscardVoiceMessageDescription)); } - builder.setPositiveButton(LocaleController.getString("DiscardVoiceMessageAction", R.string.DiscardVoiceMessageAction), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (chatActivityEnterView != null) { - chatActivityEnterView.cancelRecordingAudioVideo(); - } + builder.setPositiveButton(LocaleController.getString("DiscardVoiceMessageAction", R.string.DiscardVoiceMessageAction), (dialog, which) -> { + if (chatActivityEnterView != null) { + chatActivityEnterView.cancelRecordingAudioVideo(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -11716,12 +11388,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (dt <= 5 * 60) { replyObjectTextView.setText(LocaleController.formatString("TimeToEdit", R.string.TimeToEdit, String.format("%d:%02d", dt / 60, dt % 60))); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - checkEditTimer(); - } - }, 1000); + AndroidUtilities.runOnUIThread(this::checkEditTimer, 1000); } else { chatActivityEnterView.onEditTimeExpired(); replyObjectTextView.setText(LocaleController.formatString("TimeToEditExpired", R.string.TimeToEditExpired)); @@ -11865,12 +11532,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not name = ""; } builder.setMessage(LocaleController.formatString("BotPermissionGameAlert", R.string.BotPermissionGameAlert, name)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - showOpenGameAlert(game, messageObject, urlStr, false, uid); - MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("askgame_" + uid, false).commit(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + showOpenGameAlert(game, messageObject, urlStr, false, uid); + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("askgame_" + uid, false).commit(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -11892,12 +11556,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.formatString("OpenUrlAlert", R.string.OpenUrlAlert, url)); - builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Browser.openUrl(getParentActivity(), url, inlineReturn == 0); - } - }); + builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), (dialogInterface, i) -> Browser.openUrl(getParentActivity(), url, inlineReturn == 0)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } @@ -12189,20 +11848,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (longPress) { BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); builder.setTitle(urlFinal); - builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, final int which) { - if (which == 0) { - Browser.openUrl(getParentActivity(), urlFinal, inlineReturn == 0, false); - } else if (which == 1) { - String url = urlFinal; - if (url.startsWith("mailto:")) { - url = url.substring(7); - } else if (url.startsWith("tel:")) { - url = url.substring(4); - } - AndroidUtilities.addToClipboard(url); + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { + if (which == 0) { + Browser.openUrl(getParentActivity(), urlFinal, inlineReturn == 0, false); + } else if (which == 1) { + String url1 = urlFinal; + if (url1.startsWith("mailto:")) { + url1 = url1.substring(7); + } else if (url1.startsWith("tel:")) { + url1 = url1.substring(4); } + AndroidUtilities.addToClipboard(url1); } }); showDialog(builder.create()); @@ -12229,7 +11885,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h) { - EmbedBottomSheet.show(mContext, title, description, originalUrl, url, w, h); + try { + EmbedBottomSheet.show(mContext, title, description, originalUrl, url, w, h); + } catch (Throwable e) { + FileLog.e(e); + } } @Override @@ -12446,20 +12106,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not view = new ChatUnreadCell(mContext); } else if (viewType == 3) { view = new BotHelpCell(mContext); - ((BotHelpCell) view).setDelegate(new BotHelpCell.BotHelpCellDelegate() { - @Override - public void didPressUrl(String url) { - if (url.startsWith("@")) { - MessagesController.getInstance(currentAccount).openByUserName(url.substring(1), ChatActivity.this, 0); - } else if (url.startsWith("#") || url.startsWith("$")) { - DialogsActivity fragment = new DialogsActivity(null); - fragment.setSearchString(url); - presentFragment(fragment); - } else if (url.startsWith("/")) { - chatActivityEnterView.setCommand(null, url, false, false); - if (chatActivityEnterView.getFieldText() == null) { - hideFieldPanel(); - } + ((BotHelpCell) view).setDelegate(url -> { + if (url.startsWith("@")) { + MessagesController.getInstance(currentAccount).openByUserName(url.substring(1), ChatActivity.this, 0); + } else if (url.startsWith("#") || url.startsWith("$")) { + DialogsActivity fragment = new DialogsActivity(null); + fragment.setSearchString(url); + presentFragment(fragment); + } else if (url.startsWith("/")) { + chatActivityEnterView.setCommand(null, url, false, false); + if (chatActivityEnterView.getFieldText() == null) { + hideFieldPanel(); } } }); @@ -12827,21 +12484,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate selectedBackgroundDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - updateVisibleRows(); - if (chatActivityEnterView != null && chatActivityEnterView.getEmojiView() != null) { - chatActivityEnterView.getEmojiView().updateUIColors(); - } + ThemeDescription.ThemeDescriptionDelegate selectedBackgroundDelegate = () -> { + updateVisibleRows(); + if (chatActivityEnterView != null && chatActivityEnterView.getEmojiView() != null) { + chatActivityEnterView.getEmojiView().updateUIColors(); } }; - ThemeDescription.ThemeDescriptionDelegate attachAlertDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (chatAttachAlert != null) { - chatAttachAlert.checkColors(); - } + ThemeDescription.ThemeDescriptionDelegate attachAlertDelegate = () -> { + if (chatAttachAlert != null) { + chatAttachAlert.checkColors(); } }; return new ThemeDescription[]{ @@ -12968,7 +12619,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inContactNameText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outContactNameText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inContactPhoneText), + new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inContactPhoneSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outContactPhoneText), + new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outContactPhoneSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_mediaProgress), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inAudioProgress), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outAudioProgress), @@ -12982,7 +12635,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_adminSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outTimeSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inAudioPerfomerText), + new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inAudioPerfomerSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outAudioPerfomerText), + new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outAudioPerfomerSelectedText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inAudioTitleText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outAudioTitleText), new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inAudioDurationText), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index 55086b501..ed350c042 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; @@ -202,44 +201,35 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - final TLRPC.ChatParticipant participant; - int user_id = 0; - int promoted_by = 0; - boolean canEditAdmin = false; - if (listView.getAdapter() == listViewAdapter) { - participant = listViewAdapter.getItem(position); - if (participant != null) { - user_id = participant.user_id; - } + listView.setOnItemClickListener((view, position) -> { + final TLRPC.ChatParticipant participant; + int user_id = 0; + int promoted_by = 0; + boolean canEditAdmin = false; + if (listView.getAdapter() == listViewAdapter) { + participant = listViewAdapter.getItem(position); + if (participant != null) { + user_id = participant.user_id; + } + } else { + TLObject object = searchListViewAdapter.getItem(position); + if (object instanceof TLRPC.ChatParticipant) { + participant = (TLRPC.ChatParticipant) object; } else { - TLObject object = searchListViewAdapter.getItem(position); - if (object instanceof TLRPC.ChatParticipant) { - participant = (TLRPC.ChatParticipant) object; - } else { - participant = null; - } - if (participant != null) { - user_id = participant.user_id; - } + participant = null; } - if (user_id != 0) { - Bundle args = new Bundle(); - args.putInt("user_id", user_id); - presentFragment(new ProfileActivity(args)); + if (participant != null) { + user_id = participant.user_id; } } + if (user_id != 0) { + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ProfileActivity(args)); + } }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - return !(getParentActivity() == null || listView.getAdapter() != listViewAdapter) && createMenuForParticipant(listViewAdapter.getItem(position), false); - - } - }); + listView.setOnItemLongClickListener((view, position) -> !(getParentActivity() == null || listView.getAdapter() != listViewAdapter) && createMenuForParticipant(listViewAdapter.getItem(position), false)); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -291,12 +281,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente items.add(LocaleController.getString("KickFromGroup", R.string.KickFromGroup)); actions.add(0); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(items.toArray(new CharSequence[actions.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, final int i) { - if (actions.get(i) == 0) { - MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), info); - } + builder.setItems(items.toArray(new CharSequence[actions.size()]), (dialogInterface, i) -> { + if (actions.get(i) == 0) { + MessagesController.getInstance(currentAccount).deleteUserFromChat(chatId, MessagesController.getInstance(currentAccount).getUser(participant.user_id), info); } }); showDialog(builder.create()); @@ -376,76 +363,66 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - final ArrayList contactsCopy = new ArrayList<>(); - contactsCopy.addAll(participants); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(new ArrayList(), new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + AndroidUtilities.runOnUIThread(() -> { + final ArrayList contactsCopy = new ArrayList<>(participants); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>(), new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList resultArray = new ArrayList<>(); - ArrayList resultArrayNames = new ArrayList<>(); + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); - for (int a = 0; a < contactsCopy.size(); a++) { - TLRPC.ChatParticipant participant = contactsCopy.get(a); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(participant.user_id); + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.ChatParticipant participant = contactsCopy.get(a); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(participant.user_id); - String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (user.username != null && user.username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray.add(participant); - break; - } - } - } - updateSearchResults(resultArray, resultArrayNames); + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; } - }); - } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(participant); + break; + } + } + } + updateSearchResults(resultArray, resultArrayNames); + }); }); } private void updateSearchResults(final ArrayList users, final ArrayList names) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchResult = users; - searchResultNames = names; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); }); } @@ -467,16 +444,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = new ManageChatUserCell(mContext, 2, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - TLObject object = getItem((Integer) cell.getTag()); - if (object instanceof TLRPC.ChatParticipant) { - TLRPC.ChatParticipant participant = (TLRPC.ChatParticipant) getItem((Integer) cell.getTag()); - return createMenuForParticipant(participant, !click); - } else { - return false; - } + ((ManageChatUserCell) view).setDelegate((cell, click) -> { + TLObject object = getItem((Integer) cell.getTag()); + if (object instanceof TLRPC.ChatParticipant) { + TLRPC.ChatParticipant participant = (TLRPC.ChatParticipant) getItem((Integer) cell.getTag()); + return createMenuForParticipant(participant, !click); + } else { + return false; } }); return new RecyclerListView.Holder(view); @@ -549,12 +523,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente case 0: view = new ManageChatUserCell(mContext, 1, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ((ManageChatUserCell) view).setDelegate(new ManageChatUserCell.ManageChatUserCellDelegate() { - @Override - public boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click) { - TLRPC.ChatParticipant participant = listViewAdapter.getItem((Integer) cell.getTag()); - return createMenuForParticipant(participant, !click); - } + ((ManageChatUserCell) view).setDelegate((cell, click) -> { + TLRPC.ChatParticipant participant = listViewAdapter.getItem((Integer) cell.getTag()); + return createMenuForParticipant(participant, !click); }); break; case 1: @@ -614,16 +585,13 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof ManageChatUserCell) { - ((ManageChatUserCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof ManageChatUserCell) { + ((ManageChatUserCell) child).update(0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index deb026fa0..489105444 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -13,6 +13,9 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.TypedValue; import android.view.Gravity; @@ -37,7 +40,6 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; @@ -49,6 +51,7 @@ import org.telegram.ui.Cells.AccountSelectCell; import org.telegram.ui.Cells.RadioColorCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.ProfileNotificationsActivity; import org.telegram.ui.ReportOtherActivity; import java.util.ArrayList; @@ -66,6 +69,8 @@ public class AlertsCreator { showSimpleAlert(fragment, LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (error.text.startsWith("FLOOD_WAIT")) { showSimpleAlert(fragment, LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if ("APP_VERSION_OUTDATED".equals(error.text)) { + showUpdateAppAlert(fragment.getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); } else { showSimpleAlert(fragment, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); } @@ -254,12 +259,7 @@ public class AlertsCreator { builder.setMessage(text); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); if (updateApp) { - builder.setNegativeButton(LocaleController.getString("UpdateApp", R.string.UpdateApp), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Browser.openUrl(context, BuildVars.PLAYSTORE_APP_URL); - } - }); + builder.setNegativeButton(LocaleController.getString("UpdateApp", R.string.UpdateApp), (dialog, which) -> Browser.openUrl(context, BuildVars.PLAYSTORE_APP_URL)); } return builder.show(); } @@ -285,6 +285,119 @@ public class AlertsCreator { return dialog; } + public static void showCustomNotificationsDialog(BaseFragment parentFragment, long did, int currentAccount, MessagesStorage.IntCallback callback) { + if (parentFragment == null || parentFragment.getParentActivity() == null) { + return; + } + boolean enabled; + boolean defaultEnabled; + if ((int) did < 0) { + defaultEnabled = MessagesController.getNotificationsSettings(currentAccount).getBoolean("EnableGroup", true); + } else { + defaultEnabled = MessagesController.getNotificationsSettings(currentAccount).getBoolean("EnableAll", true); + } + + String[] descriptions = new String[]{ + defaultEnabled ? LocaleController.getString("NotificationsDefaultOn", R.string.NotificationsDefaultOn) : LocaleController.getString("NotificationsDefaultOff", R.string.NotificationsDefaultOff), + LocaleController.getString("NotificationsTurnOn", R.string.NotificationsTurnOn), + LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Hours", 1)), + LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Days", 2)), + LocaleController.getString("NotificationsCustomize", R.string.NotificationsCustomize), + LocaleController.getString("NotificationsTurnOff", R.string.NotificationsTurnOff) + }; + + int[] icons = new int[]{ + defaultEnabled ? R.drawable.notifications_s_on : R.drawable.notifications_s_off, + R.drawable.notifications_s_on, + R.drawable.notifications_s_1h, + R.drawable.notifications_s_2d, + R.drawable.notifications_s_custom, + R.drawable.notifications_s_off + }; + + final LinearLayout linearLayout = new LinearLayout(parentFragment.getParentActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + + for (int a = 0; a < descriptions.length; a++) { + TextView textView = new TextView(parentFragment.getParentActivity()); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + Drawable drawable = parentFragment.getParentActivity().getResources().getDrawable(icons[a]); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogIcon), PorterDuff.Mode.MULTIPLY)); + textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); + textView.setTag(a); + textView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + textView.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); + textView.setSingleLine(true); + textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + textView.setCompoundDrawablePadding(AndroidUtilities.dp(26)); + textView.setText(descriptions[a]); + linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP)); + textView.setOnClickListener(v -> { + int i = (Integer) v.getTag(); + if (i == 0 || i == 1) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + if (i == 0) { + editor.remove("notify2_" + did); + } else { + editor.putInt("notify2_" + did, 0); + } + MessagesStorage.getInstance(currentAccount).setDialogFlags(did, 0); + editor.commit(); + TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + } + NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); + } else if (i == 4) { + Bundle args = new Bundle(); + args.putLong("dialog_id", did); + parentFragment.presentFragment(new ProfileNotificationsActivity(args)); + } else { + int untilTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + if (i == 2) { + untilTime += 60 * 60; + } else if (i == 3) { + untilTime += 60 * 60 * 48; + } else if (i == 5) { + untilTime = Integer.MAX_VALUE; + } + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + long flags; + if (i == 5) { + editor.putInt("notify2_" + did, 2); + flags = 1; + } else { + editor.putInt("notify2_" + did, 3); + editor.putInt("notifyuntil_" + did, untilTime); + flags = ((long) untilTime << 32) | 1; + } + NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); + MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); + editor.commit(); + TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + dialog.notify_settings.mute_until = untilTime; + } + NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); + } + if (callback != null) { + callback.run(i); + } + parentFragment.dismissCurrentDialig(); + }); + } + AlertDialog.Builder builder = new AlertDialog.Builder(parentFragment.getParentActivity()); + builder.setTitle(LocaleController.getString("Notifications", R.string.Notifications)); + builder.setView(linearLayout); + parentFragment.showDialog(builder.create()); + } + public static AlertDialog showSecretLocationAlert(Context context, int currentAccount, final Runnable onSelectRunnable, boolean inChat) { ArrayList arrayList = new ArrayList<>(); int providers = MessagesController.getInstance(currentAccount).availableMapProviders; @@ -300,13 +413,10 @@ public class AlertsCreator { arrayList.add(LocaleController.getString("MapPreviewProviderNobody", R.string.MapPreviewProviderNobody)); AlertDialog.Builder builder = new AlertDialog.Builder(context) .setTitle(LocaleController.getString("ChooseMapPreviewProvider", R.string.ChooseMapPreviewProvider)) - .setItems(arrayList.toArray(new String[arrayList.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedConfig.setSecretMapPreviewType(which); - if (onSelectRunnable != null) { - onSelectRunnable.run(); - } + .setItems(arrayList.toArray(new String[arrayList.size()]), (dialog, which) -> { + SharedConfig.setSecretMapPreviewType(which); + if (onSelectRunnable != null) { + onSelectRunnable.run(); } }); if (!inChat) { @@ -357,7 +467,7 @@ public class AlertsCreator { void didSelectDate(int year, int month, int dayOfMonth); } - public static AlertDialog.Builder createDatePickerDialog(Context context, int minYear, int maxYear, String title, final boolean checkMinDate, final DatePickerDelegate datePickerDelegate) { + public static AlertDialog.Builder createDatePickerDialog(Context context, int minYear, int maxYear, int currentYearDiff, int selectedDay, int selectedMonth, int selectedYear, String title, final boolean checkMinDate, final DatePickerDelegate datePickerDelegate) { if (context == null) { return null; } @@ -370,39 +480,26 @@ public class AlertsCreator { final NumberPicker dayPicker = new NumberPicker(context); final NumberPicker yearPicker = new NumberPicker(context); - monthPicker.setMinValue(0); - monthPicker.setMaxValue(11); - linearLayout.addView(monthPicker, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.4f)); - monthPicker.setFormatter(new NumberPicker.Formatter() { - @Override - public String format(int value) { - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.MONTH, value); - return calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()); - } - }); - monthPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - updateDayPicker(dayPicker, monthPicker, yearPicker); - } - }); - monthPicker.setOnScrollListener(new NumberPicker.OnScrollListener() { - @Override - public void onScrollStateChange(NumberPicker view, int scrollState) { - if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { - checkPickerDate(dayPicker, monthPicker, yearPicker); - } + linearLayout.addView(dayPicker, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.3f)); + dayPicker.setOnScrollListener((view, scrollState) -> { + if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { + checkPickerDate(dayPicker, monthPicker, yearPicker); } }); - linearLayout.addView(dayPicker, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.2f)); - dayPicker.setOnScrollListener(new NumberPicker.OnScrollListener() { - @Override - public void onScrollStateChange(NumberPicker view, int scrollState) { - if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { - checkPickerDate(dayPicker, monthPicker, yearPicker); - } + monthPicker.setMinValue(0); + monthPicker.setMaxValue(11); + linearLayout.addView(monthPicker, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.3f)); + monthPicker.setFormatter(value -> { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.MONTH, value); + return calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()); + }); + monthPicker.setOnValueChangedListener((picker, oldVal, newVal) -> updateDayPicker(dayPicker, monthPicker, yearPicker)); + monthPicker.setOnScrollListener((view, scrollState) -> { + if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { + checkPickerDate(dayPicker, monthPicker, yearPicker); } }); @@ -411,20 +508,12 @@ public class AlertsCreator { final int currentYear = calendar.get(Calendar.YEAR); yearPicker.setMinValue(currentYear + minYear); yearPicker.setMaxValue(currentYear + maxYear); - yearPicker.setValue(currentYear); + yearPicker.setValue(currentYear + currentYearDiff); linearLayout.addView(yearPicker, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 0.4f)); - yearPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - updateDayPicker(dayPicker, monthPicker, yearPicker); - } - }); - yearPicker.setOnScrollListener(new NumberPicker.OnScrollListener() { - @Override - public void onScrollStateChange(NumberPicker view, int scrollState) { - if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { - checkPickerDate(dayPicker, monthPicker, yearPicker); - } + yearPicker.setOnValueChangedListener((picker, oldVal, newVal) -> updateDayPicker(dayPicker, monthPicker, yearPicker)); + yearPicker.setOnScrollListener((view, scrollState) -> { + if (checkMinDate && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE) { + checkPickerDate(dayPicker, monthPicker, yearPicker); } }); updateDayPicker(dayPicker, monthPicker, yearPicker); @@ -432,18 +521,21 @@ public class AlertsCreator { checkPickerDate(dayPicker, monthPicker, yearPicker); } + if (selectedDay != -1) { + dayPicker.setValue(selectedDay); + monthPicker.setValue(selectedMonth); + yearPicker.setValue(selectedYear); + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(title); builder.setView(linearLayout); - builder.setPositiveButton(LocaleController.getString("Set", R.string.Set), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (checkMinDate) { - checkPickerDate(dayPicker, monthPicker, yearPicker); - } - datePickerDelegate.didSelectDate(yearPicker.getValue(), monthPicker.getValue(), dayPicker.getValue()); + builder.setPositiveButton(LocaleController.getString("Set", R.string.Set), (dialog, which) -> { + if (checkMinDate) { + checkPickerDate(dayPicker, monthPicker, yearPicker); } + datePickerDelegate.didSelectDate(yearPicker.getValue(), monthPicker.getValue(), dayPicker.getValue()); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); return builder; @@ -462,42 +554,39 @@ public class AlertsCreator { LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Days", 2)), LocaleController.getString("MuteDisable", R.string.MuteDisable) }; - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - int untilTime = ConnectionsManager.getInstance(UserConfig.selectedAccount).getCurrentTime(); - if (i == 0) { - untilTime += 60 * 60; - } else if (i == 1) { - untilTime += 60 * 60 * 8; - } else if (i == 2) { - untilTime += 60 * 60 * 48; - } else if (i == 3) { - untilTime = Integer.MAX_VALUE; - } + builder.setItems(items, (dialogInterface, i) -> { + int untilTime = ConnectionsManager.getInstance(UserConfig.selectedAccount).getCurrentTime(); + if (i == 0) { + untilTime += 60 * 60; + } else if (i == 1) { + untilTime += 60 * 60 * 8; + } else if (i == 2) { + untilTime += 60 * 60 * 48; + } else if (i == 3) { + untilTime = Integer.MAX_VALUE; + } - SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - long flags; - if (i == 3) { - editor.putInt("notify2_" + dialog_id, 2); - flags = 1; - } else { - editor.putInt("notify2_" + dialog_id, 3); - editor.putInt("notifyuntil_" + dialog_id, untilTime); - flags = ((long) untilTime << 32) | 1; - } - NotificationsController.getInstance(UserConfig.selectedAccount).removeNotificationsForDialog(dialog_id); - MessagesStorage.getInstance(UserConfig.selectedAccount).setDialogFlags(dialog_id, flags); - editor.commit(); - TLRPC.TL_dialog dialog = MessagesController.getInstance(UserConfig.selectedAccount).dialogs_dict.get(dialog_id); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - dialog.notify_settings.mute_until = untilTime; - } - NotificationsController.getInstance(UserConfig.selectedAccount).updateServerNotificationsSettings(dialog_id); - } - } + SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences.edit(); + long flags; + if (i == 3) { + editor.putInt("notify2_" + dialog_id, 2); + flags = 1; + } else { + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, untilTime); + flags = ((long) untilTime << 32) | 1; + } + NotificationsController.getInstance(UserConfig.selectedAccount).removeNotificationsForDialog(dialog_id); + MessagesStorage.getInstance(UserConfig.selectedAccount).setDialogFlags(dialog_id, flags); + editor.commit(); + TLRPC.TL_dialog dialog = MessagesController.getInstance(UserConfig.selectedAccount).dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + dialog.notify_settings.mute_until = untilTime; + } + NotificationsController.getInstance(UserConfig.selectedAccount).updateServerNotificationsSettings(dialog_id); + } ); return builder.create(); } @@ -515,51 +604,45 @@ public class AlertsCreator { LocaleController.getString("ReportChatPornography", R.string.ReportChatPornography), LocaleController.getString("ReportChatOther", R.string.ReportChatOther) }; - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 3) { - Bundle args = new Bundle(); - args.putLong("dialog_id", dialog_id); - args.putLong("message_id", messageId); - parentFragment.presentFragment(new ReportOtherActivity(args)); - return; - } - TLObject req; - TLRPC.InputPeer peer = MessagesController.getInstance(UserConfig.selectedAccount).getInputPeer((int) dialog_id); - if (messageId != 0) { - TLRPC.TL_messages_report request = new TLRPC.TL_messages_report(); - request.peer = peer; - request.id.add(messageId); - if (i == 0) { - request.reason = new TLRPC.TL_inputReportReasonSpam(); - } else if (i == 1) { - request.reason = new TLRPC.TL_inputReportReasonViolence(); - } else if (i == 2) { - request.reason = new TLRPC.TL_inputReportReasonPornography(); - } - req = request; - } else { - TLRPC.TL_account_reportPeer request = new TLRPC.TL_account_reportPeer(); - request.peer = peer; - if (i == 0) { - request.reason = new TLRPC.TL_inputReportReasonSpam(); - } else if (i == 1) { - request.reason = new TLRPC.TL_inputReportReasonViolence(); - } else if (i == 2) { - request.reason = new TLRPC.TL_inputReportReasonPornography(); - } - req = request; - } - ConnectionsManager.getInstance(UserConfig.selectedAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - - } - }); - Toast.makeText(context, LocaleController.getString("ReportChatSent", R.string.ReportChatSent), Toast.LENGTH_SHORT).show(); - } + builder.setItems(items, (dialogInterface, i) -> { + if (i == 3) { + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + args.putLong("message_id", messageId); + parentFragment.presentFragment(new ReportOtherActivity(args)); + return; + } + TLObject req; + TLRPC.InputPeer peer = MessagesController.getInstance(UserConfig.selectedAccount).getInputPeer((int) dialog_id); + if (messageId != 0) { + TLRPC.TL_messages_report request = new TLRPC.TL_messages_report(); + request.peer = peer; + request.id.add(messageId); + if (i == 0) { + request.reason = new TLRPC.TL_inputReportReasonSpam(); + } else if (i == 1) { + request.reason = new TLRPC.TL_inputReportReasonViolence(); + } else if (i == 2) { + request.reason = new TLRPC.TL_inputReportReasonPornography(); } + req = request; + } else { + TLRPC.TL_account_reportPeer request = new TLRPC.TL_account_reportPeer(); + request.peer = peer; + if (i == 0) { + request.reason = new TLRPC.TL_inputReportReasonSpam(); + } else if (i == 1) { + request.reason = new TLRPC.TL_inputReportReasonViolence(); + } else if (i == 2) { + request.reason = new TLRPC.TL_inputReportReasonPornography(); + } + req = request; + } + ConnectionsManager.getInstance(UserConfig.selectedAccount).sendRequest(req, (response, error) -> { + + }); + Toast.makeText(context, LocaleController.getString("ReportChatSent", R.string.ReportChatSent), Toast.LENGTH_SHORT).show(); + } ); return builder.create(); } @@ -618,12 +701,7 @@ public class AlertsCreator { switch (error) { case "PEER_FLOOD": builder.setMessage(LocaleController.getString("NobodyLikesSpam2", R.string.NobodyLikesSpam2)); - builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(fragment.getCurrentAccount()).openByUserName("spambot", fragment, 1); - } - }); + builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), (dialogInterface, i) -> MessagesController.getInstance(fragment.getCurrentAccount()).openByUserName("spambot", fragment, 1)); break; case "USER_BLOCKED": case "USER_BOT": @@ -733,68 +811,56 @@ public class AlertsCreator { cell.setCheckColor(TextColorCell.colors[a], TextColorCell.colors[a]); cell.setTextAndValue(descriptions[a], currentColor == TextColorCell.colorsToSave[a]); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int count = linearLayout.getChildCount(); - for (int a = 0; a < count; a++) { - RadioColorCell cell = (RadioColorCell) linearLayout.getChildAt(a); - cell.setChecked(cell == v, true); - } - selectedColor[0] = TextColorCell.colorsToSave[(Integer) v.getTag()]; + cell.setOnClickListener(v -> { + int count = linearLayout.getChildCount(); + for (int a1 = 0; a1 < count; a1++) { + RadioColorCell cell1 = (RadioColorCell) linearLayout.getChildAt(a1); + cell1.setChecked(cell1 == v, true); } + selectedColor[0] = TextColorCell.colorsToSave[(Integer) v.getTag()]; }); } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("LedColor", R.string.LedColor)); builder.setView(linearLayout); - builder.setPositiveButton(LocaleController.getString("Set", R.string.Set), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int which) { - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (globalAll) { - editor.putInt("MessagesLed", selectedColor[0]); - } else if (globalGroup) { - editor.putInt("GroupLed", selectedColor[0]); - } else { - editor.putInt("color_" + dialog_id, selectedColor[0]); - } - editor.commit(); - if (onSelect != null) { - onSelect.run(); - } + builder.setPositiveButton(LocaleController.getString("Set", R.string.Set), (dialogInterface, which) -> { + final SharedPreferences preferences1 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences1.edit(); + if (globalAll) { + editor.putInt("MessagesLed", selectedColor[0]); + } else if (globalGroup) { + editor.putInt("GroupLed", selectedColor[0]); + } else { + editor.putInt("color_" + dialog_id, selectedColor[0]); + } + editor.commit(); + if (onSelect != null) { + onSelect.run(); } }); - builder.setNeutralButton(LocaleController.getString("LedDisabled", R.string.LedDisabled), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (globalAll) { - editor.putInt("MessagesLed", 0); - } else if (globalGroup) { - editor.putInt("GroupLed", 0); - } else { - editor.putInt("color_" + dialog_id, 0); - } - editor.commit(); - if (onSelect != null) { - onSelect.run(); - } + builder.setNeutralButton(LocaleController.getString("LedDisabled", R.string.LedDisabled), (dialog, which) -> { + final SharedPreferences preferences12 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences12.edit(); + if (globalAll) { + editor.putInt("MessagesLed", 0); + } else if (globalGroup) { + editor.putInt("GroupLed", 0); + } else { + editor.putInt("color_" + dialog_id, 0); + } + editor.commit(); + if (onSelect != null) { + onSelect.run(); } }); if (!globalAll && !globalGroup) { - builder.setNegativeButton(LocaleController.getString("Default", R.string.Default), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.remove("color_" + dialog_id); - editor.commit(); - if (onSelect != null) { - onSelect.run(); - } + builder.setNegativeButton(LocaleController.getString("Default", R.string.Default), (dialog, which) -> { + final SharedPreferences preferences13 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences13.edit(); + editor.remove("color_" + dialog_id); + editor.commit(); + if (onSelect != null) { + onSelect.run(); } }); } @@ -856,44 +922,41 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - selected[0] = (Integer) v.getTag(); + cell.setOnClickListener(v -> { + selected[0] = (Integer) v.getTag(); - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (dialog_id != 0) { - if (selected[0] == 0) { - editor.putInt(prefKeyPrefix + dialog_id, 0); - } else if (selected[0] == 1) { - editor.putInt(prefKeyPrefix + dialog_id, 1); - } else if (selected[0] == 2) { - editor.putInt(prefKeyPrefix + dialog_id, 3); - } else if (selected[0] == 3) { - editor.putInt(prefKeyPrefix + dialog_id, 2); - } - } else { - if (selected[0] == 0) { - editor.putInt(prefKeyPrefix, 2); - } else if (selected[0] == 1) { - editor.putInt(prefKeyPrefix, 0); - } else if (selected[0] == 2) { - editor.putInt(prefKeyPrefix, 1); - } else if (selected[0] == 3) { - editor.putInt(prefKeyPrefix, 3); - } else if (selected[0] == 4) { - editor.putInt(prefKeyPrefix, 4); - } + final SharedPreferences preferences1 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences1.edit(); + if (dialog_id != 0) { + if (selected[0] == 0) { + editor.putInt(prefKeyPrefix + dialog_id, 0); + } else if (selected[0] == 1) { + editor.putInt(prefKeyPrefix + dialog_id, 1); + } else if (selected[0] == 2) { + editor.putInt(prefKeyPrefix + dialog_id, 3); + } else if (selected[0] == 3) { + editor.putInt(prefKeyPrefix + dialog_id, 2); } - editor.commit(); - if (parentFragment != null) { - parentFragment.dismissCurrentDialig(); - } - if (onSelect != null) { - onSelect.run(); + } else { + if (selected[0] == 0) { + editor.putInt(prefKeyPrefix, 2); + } else if (selected[0] == 1) { + editor.putInt(prefKeyPrefix, 0); + } else if (selected[0] == 2) { + editor.putInt(prefKeyPrefix, 1); + } else if (selected[0] == 3) { + editor.putInt(prefKeyPrefix, 3); + } else if (selected[0] == 4) { + editor.putInt(prefKeyPrefix, 4); } } + editor.commit(); + if (parentFragment != null) { + parentFragment.dismissCurrentDialig(); + } + if (onSelect != null) { + onSelect.run(); + } }); } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); @@ -933,17 +996,14 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int num = (Integer) v.getTag(); - selected[0] = num; - int count = linearLayout.getChildCount(); - for (int a = 0; a < count; a++) { - View child = linearLayout.getChildAt(a); - if (child instanceof RadioColorCell) { - ((RadioColorCell) child).setChecked(child == v, true); - } + cell.setOnClickListener(v -> { + int num = (Integer) v.getTag(); + selected[0] = num; + int count = linearLayout.getChildCount(); + for (int a1 = 0; a1 < count; a1++) { + View child = linearLayout.getChildAt(a1); + if (child instanceof RadioColorCell) { + ((RadioColorCell) child).setChecked(child == v, true); } } }); @@ -951,19 +1011,16 @@ public class AlertsCreator { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTopImage(new ShareLocationDrawable(parentActivity, false), Theme.getColor(Theme.key_dialogTopBackground)); builder.setView(linearLayout); - builder.setPositiveButton(LocaleController.getString("ShareFile", R.string.ShareFile), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int time; - if (selected[0] == 0) { - time = 15 * 60; - } else if (selected[0] == 1) { - time = 60 * 60; - } else { - time = 8 * 60 * 60; - } - callback.run(time); + builder.setPositiveButton(LocaleController.getString("ShareFile", R.string.ShareFile), (dialog, which) -> { + int time; + if (selected[0] == 0) { + time = 15 * 60; + } else if (selected[0] == 1) { + time = 60 * 60; + } else { + time = 8 * 60 * 60; } + callback.run(time); }); builder.setNeutralButton(LocaleController.getString("Cancel", R.string.Cancel), null); return builder.create(); @@ -973,18 +1030,8 @@ public class AlertsCreator { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTopImage(R.drawable.permissions_contacts, Theme.getColor(Theme.key_dialogTopBackground)); builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("ContactsPermissionAlert", R.string.ContactsPermissionAlert))); - builder.setPositiveButton(LocaleController.getString("ContactsPermissionAlertContinue", R.string.ContactsPermissionAlertContinue), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - callback.run(1); - } - }); - builder.setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - callback.run(0); - } - }); + builder.setPositiveButton(LocaleController.getString("ContactsPermissionAlertContinue", R.string.ContactsPermissionAlertContinue), (dialog, which) -> callback.run(1)); + builder.setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), (dialog, which) -> callback.run(0)); return builder; } @@ -1028,25 +1075,22 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int num = (Integer) v.getTag(); - if (num == 0) { - selected[0] = 3; - } else if (num == 1) { - selected[0] = 0; - } else if (num == 2) { - selected[0] = 1; - } else if (num == 3) { - selected[0] = 2; - } - int count = linearLayout.getChildCount(); - for (int a = 0; a < count; a++) { - View child = linearLayout.getChildAt(a); - if (child instanceof RadioColorCell) { - ((RadioColorCell) child).setChecked(child == v, true); - } + cell.setOnClickListener(v -> { + int num = (Integer) v.getTag(); + if (num == 0) { + selected[0] = 3; + } else if (num == 1) { + selected[0] = 0; + } else if (num == 2) { + selected[0] = 1; + } else if (num == 3) { + selected[0] = 2; + } + int count = linearLayout.getChildCount(); + for (int a1 = 0; a1 < count; a1++) { + View child = linearLayout.getChildAt(a1); + if (child instanceof RadioColorCell) { + ((RadioColorCell) child).setChecked(child == v, true); } } }); @@ -1055,18 +1099,8 @@ public class AlertsCreator { builder.setTitle(LocaleController.getString("LowDiskSpaceTitle", R.string.LowDiskSpaceTitle)); builder.setMessage(LocaleController.getString("LowDiskSpaceMessage", R.string.LowDiskSpaceMessage)); builder.setView(linearLayout); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - MessagesController.getGlobalMainSettings().edit().putInt("keep_media", selected[0]).commit(); - } - }); - builder.setNeutralButton(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - parentActivity.presentFragment(new CacheControlActivity()); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> MessagesController.getGlobalMainSettings().edit().putInt("keep_media", selected[0]).commit()); + builder.setNeutralButton(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), (dialog, which) -> parentActivity.presentFragment(new CacheControlActivity())); return builder.create(); } @@ -1127,47 +1161,44 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - selected[0] = (Integer) v.getTag(); + cell.setOnClickListener(v -> { + selected[0] = (Integer) v.getTag(); - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (dialog_id != 0) { - int option; - if (selected[0] == 0) { - option = 3; - } else if (selected[0] == 1) { - option = 4; - } else if (selected[0] == 2) { - option = 5; - } else if (selected[0] == 3) { - option = 0; - } else { - option = 1; - } - editor.putInt("priority_" + dialog_id, option); + final SharedPreferences preferences1 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences1.edit(); + if (dialog_id != 0) { + int option; + if (selected[0] == 0) { + option = 3; + } else if (selected[0] == 1) { + option = 4; + } else if (selected[0] == 2) { + option = 5; + } else if (selected[0] == 3) { + option = 0; } else { - int option; - if (selected[0] == 0) { - option = 4; - } else if (selected[0] == 1) { - option = 5; - } else if (selected[0] == 2) { - option = 0; - } else { - option = 1; - } - editor.putInt(globalGroup ? "priority_group" : "priority_messages", option); + option = 1; } - editor.commit(); - if (parentFragment != null) { - parentFragment.dismissCurrentDialig(); - } - if (onSelect != null) { - onSelect.run(); + editor.putInt("priority_" + dialog_id, option); + } else { + int option; + if (selected[0] == 0) { + option = 4; + } else if (selected[0] == 1) { + option = 5; + } else if (selected[0] == 2) { + option = 0; + } else { + option = 1; } + editor.putInt(globalGroup ? "priority_group" : "priority_messages", option); + } + editor.commit(); + if (parentFragment != null) { + parentFragment.dismissCurrentDialig(); + } + if (onSelect != null) { + onSelect.run(); } }); } @@ -1203,21 +1234,18 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(descriptions[a], selected[0] == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - selected[0] = (Integer) v.getTag(); + cell.setOnClickListener(v -> { + selected[0] = (Integer) v.getTag(); - final SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt(globalGroup ? "popupGroup" : "popupAll", selected[0]); - editor.commit(); - if (parentFragment != null) { - parentFragment.dismissCurrentDialig(); - } - if (onSelect != null) { - onSelect.run(); - } + final SharedPreferences preferences1 = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); + SharedPreferences.Editor editor = preferences1.edit(); + editor.putInt(globalGroup ? "popupGroup" : "popupAll", selected[0]); + editor.commit(); + if (parentFragment != null) { + parentFragment.dismissCurrentDialig(); + } + if (onSelect != null) { + onSelect.run(); } }); } @@ -1239,16 +1267,13 @@ public class AlertsCreator { cell.setCheckColor(Theme.getColor(Theme.key_radioBackground), Theme.getColor(Theme.key_dialogRadioBackgroundChecked)); cell.setTextAndValue(options[a], selected == a); linearLayout.addView(cell); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int sel = (Integer) v.getTag(); + cell.setOnClickListener(v -> { + int sel = (Integer) v.getTag(); - if (parentFragment != null) { - parentFragment.dismissCurrentDialig(); - } - listener.onClick(null, sel); + if (parentFragment != null) { + parentFragment.dismissCurrentDialig(); } + listener.onClick(null, sel); }); } @@ -1279,50 +1304,44 @@ public class AlertsCreator { } else if (encryptedChat.ttl == 0) { numberPicker.setValue(0); } - numberPicker.setFormatter(new NumberPicker.Formatter() { - @Override - public String format(int value) { - if (value == 0) { - return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever); - } else if (value >= 1 && value < 16) { - return LocaleController.formatTTLString(value); - } else if (value == 16) { - return LocaleController.formatTTLString(30); - } else if (value == 17) { - return LocaleController.formatTTLString(60); - } else if (value == 18) { - return LocaleController.formatTTLString(60 * 60); - } else if (value == 19) { - return LocaleController.formatTTLString(60 * 60 * 24); - } else if (value == 20) { - return LocaleController.formatTTLString(60 * 60 * 24 * 7); - } - return ""; + numberPicker.setFormatter(value -> { + if (value == 0) { + return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever); + } else if (value >= 1 && value < 16) { + return LocaleController.formatTTLString(value); + } else if (value == 16) { + return LocaleController.formatTTLString(30); + } else if (value == 17) { + return LocaleController.formatTTLString(60); + } else if (value == 18) { + return LocaleController.formatTTLString(60 * 60); + } else if (value == 19) { + return LocaleController.formatTTLString(60 * 60 * 24); + } else if (value == 20) { + return LocaleController.formatTTLString(60 * 60 * 24 * 7); } + return ""; }); builder.setView(numberPicker); - builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int oldValue = encryptedChat.ttl; - which = numberPicker.getValue(); - if (which >= 0 && which < 16) { - encryptedChat.ttl = which; - } else if (which == 16) { - encryptedChat.ttl = 30; - } else if (which == 17) { - encryptedChat.ttl = 60; - } else if (which == 18) { - encryptedChat.ttl = 60 * 60; - } else if (which == 19) { - encryptedChat.ttl = 60 * 60 * 24; - } else if (which == 20) { - encryptedChat.ttl = 60 * 60 * 24 * 7; - } - if (oldValue != encryptedChat.ttl) { - SecretChatHelper.getInstance(UserConfig.selectedAccount).sendTTLMessage(encryptedChat, null); - MessagesStorage.getInstance(UserConfig.selectedAccount).updateEncryptedChatTTL(encryptedChat); - } + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), (dialog, which) -> { + int oldValue = encryptedChat.ttl; + which = numberPicker.getValue(); + if (which >= 0 && which < 16) { + encryptedChat.ttl = which; + } else if (which == 16) { + encryptedChat.ttl = 30; + } else if (which == 17) { + encryptedChat.ttl = 60; + } else if (which == 18) { + encryptedChat.ttl = 60 * 60; + } else if (which == 19) { + encryptedChat.ttl = 60 * 60 * 24; + } else if (which == 20) { + encryptedChat.ttl = 60 * 60 * 24 * 7; + } + if (oldValue != encryptedChat.ttl) { + SecretChatHelper.getInstance(UserConfig.selectedAccount).sendTTLMessage(encryptedChat, null); + MessagesStorage.getInstance(UserConfig.selectedAccount).updateEncryptedChatTTL(encryptedChat); } }); return builder; @@ -1351,16 +1370,13 @@ public class AlertsCreator { cell.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (alertDialog[0] != null) { - alertDialog[0].setOnDismissListener(null); - } - dismissRunnable.run(); - AccountSelectCell cell = (AccountSelectCell) v; - delegate.didSelectAccount(cell.getAccountNumber()); + cell.setOnClickListener(v -> { + if (alertDialog[0] != null) { + alertDialog[0].setOnDismissListener(null); } + dismissRunnable.run(); + AccountSelectCell cell1 = (AccountSelectCell) v; + delegate.didSelectAccount(cell1.getAccountNumber()); }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedArrowDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedArrowDrawable.java index c6c66cb25..e2a4bbcad 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedArrowDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedArrowDrawable.java @@ -80,6 +80,10 @@ public class AnimatedArrowDrawable extends Drawable { } } + public void setColor(int color) { + paint.setColor(color); + } + public float getAnimationProgress() { return animProgress; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index 20415697f..66cccbaed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -78,14 +78,11 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { private View parentView = null; private View secondParentView = null; - protected final Runnable mInvalidateTask = new Runnable() { - @Override - public void run() { - if (secondParentView != null) { - secondParentView.invalidate(); - } else if (parentView != null) { - parentView.invalidate(); - } + protected final Runnable mInvalidateTask = () -> { + if (secondParentView != null) { + secondParentView.invalidate(); + } else if (parentView != null) { + parentView.invalidate(); } }; @@ -159,14 +156,11 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { } }; - private final Runnable mStartTask = new Runnable() { - @Override - public void run() { - if (secondParentView != null) { - secondParentView.invalidate(); - } else if (parentView != null) { - parentView.invalidate(); - } + private final Runnable mStartTask = () -> { + if (secondParentView != null) { + secondParentView.invalidate(); + } else if (parentView != null) { + parentView.invalidate(); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index 6919cd157..c2b1f7668 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -13,7 +13,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Paint; @@ -406,58 +405,54 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. placeholderImageView.setRoundRadius(AndroidUtilities.dp(20)); placeholderImageView.setPivotX(0); placeholderImageView.setPivotY(0); - placeholderImageView.setOnClickListener(new View.OnClickListener() { + placeholderImageView.setOnClickListener(view -> { + if (animatorSet != null) { + animatorSet.cancel(); + animatorSet = null; + } + animatorSet = new AnimatorSet(); + if (scrollOffsetY <= actionBar.getMeasuredHeight()) { + animatorSet.playTogether(ObjectAnimator.ofFloat(AudioPlayerAlert.this, "fullAnimationProgress", isInFullMode ? 0.0f : 1.0f)); + } else { + animatorSet.playTogether(ObjectAnimator.ofFloat(AudioPlayerAlert.this, "fullAnimationProgress", isInFullMode ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(actionBar, "alpha", isInFullMode ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(shadow, "alpha", isInFullMode ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(shadow2, "alpha", isInFullMode ? 0.0f : 1.0f)); + } - @Override - public void onClick(View view) { - if (animatorSet != null) { - animatorSet.cancel(); - animatorSet = null; - } - animatorSet = new AnimatorSet(); - if (scrollOffsetY <= actionBar.getMeasuredHeight()) { - animatorSet.playTogether(ObjectAnimator.ofFloat(AudioPlayerAlert.this, "fullAnimationProgress", isInFullMode ? 0.0f : 1.0f)); - } else { - animatorSet.playTogether(ObjectAnimator.ofFloat(AudioPlayerAlert.this, "fullAnimationProgress", isInFullMode ? 0.0f : 1.0f), - ObjectAnimator.ofFloat(actionBar, "alpha", isInFullMode ? 0.0f : 1.0f), - ObjectAnimator.ofFloat(shadow, "alpha", isInFullMode ? 0.0f : 1.0f), - ObjectAnimator.ofFloat(shadow2, "alpha", isInFullMode ? 0.0f : 1.0f)); - } - - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.setDuration(250); - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation.equals(animatorSet)) { - if (!isInFullMode) { - listView.setScrollEnabled(true); - if (hasOptions) { - menuItem.setVisibility(View.INVISIBLE); - } - searchItem.setVisibility(View.VISIBLE); - } else { - if (hasOptions) { - menuItem.setVisibility(View.VISIBLE); - } - searchItem.setVisibility(View.INVISIBLE); + animatorSet.setInterpolator(new DecelerateInterpolator()); + animatorSet.setDuration(250); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animation.equals(animatorSet)) { + if (!isInFullMode) { + listView.setScrollEnabled(true); + if (hasOptions) { + menuItem.setVisibility(View.INVISIBLE); } - animatorSet = null; + searchItem.setVisibility(View.VISIBLE); + } else { + if (hasOptions) { + menuItem.setVisibility(View.VISIBLE); + } + searchItem.setVisibility(View.INVISIBLE); } + animatorSet = null; } - }); - animatorSet.start(); - if (hasOptions) { - menuItem.setVisibility(View.VISIBLE); - } - searchItem.setVisibility(View.VISIBLE); - isInFullMode = !isInFullMode; - listView.setScrollEnabled(false); - if (isInFullMode) { - shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(20 + 48)); - } else { - shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(10)); } + }); + animatorSet.start(); + if (hasOptions) { + menuItem.setVisibility(View.VISIBLE); + } + searchItem.setVisibility(View.VISIBLE); + isInFullMode = !isInFullMode; + listView.setScrollEnabled(false); + if (isInFullMode) { + shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(20 + 48)); + } else { + shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(10)); } }); @@ -485,26 +480,11 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. optionsButton.addSubItem(2, LocaleController.getString("ShareFile", R.string.ShareFile)); //optionsButton.addSubItem(3, LocaleController.getString("Delete", R.string.Delete)); optionsButton.addSubItem(4, LocaleController.getString("ShowInChat", R.string.ShowInChat)); - optionsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - optionsButton.toggleSubMenu(); - } - }); - optionsButton.setDelegate(new ActionBarMenuItem.ActionBarMenuItemDelegate() { - @Override - public void onItemClick(int id) { - onSubItemClick(id); - } - }); + optionsButton.setOnClickListener(v -> optionsButton.toggleSubMenu()); + optionsButton.setDelegate(this::onSubItemClick); seekBarView = new SeekBarView(context); - seekBarView.setDelegate(new SeekBarView.SeekBarViewDelegate() { - @Override - public void onSeekBarDrag(float progress) { - MediaController.getInstance().seekToProgress(MediaController.getInstance().getPlayingMessageObject(), progress); - } - }); + seekBarView.setDelegate(progress -> MediaController.getInstance().seekToProgress(MediaController.getInstance().getPlayingMessageObject(), progress)); playerLayout.addView(seekBarView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.TOP | Gravity.LEFT, 8, 62, 8, 0)); progressView = new LineProgressView(context); @@ -541,12 +521,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. shuffleButton.setLongClickEnabled(false); shuffleButton.setAdditionalOffset(-AndroidUtilities.dp(10)); bottomView.addView(shuffleButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - shuffleButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - shuffleButton.toggleSubMenu(); - } - }); + shuffleButton.setOnClickListener(v -> shuffleButton.toggleSubMenu()); TextView textView = shuffleButton.addSubItem(1, LocaleController.getString("ReverseOrder", R.string.ReverseOrder)); textView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(16), 0); @@ -560,13 +535,10 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. textView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); textView.setCompoundDrawablesWithIntrinsicBounds(playOrderButtons[1], null, null, null); - shuffleButton.setDelegate(new ActionBarMenuItem.ActionBarMenuItemDelegate() { - @Override - public void onItemClick(int id) { - MediaController.getInstance().toggleShuffleMusic(id); - updateShuffleButton(); - listAdapter.notifyDataSetChanged(); - } + shuffleButton.setDelegate(id -> { + MediaController.getInstance().toggleShuffleMusic(id); + updateShuffleButton(); + listAdapter.notifyDataSetChanged(); }); ImageView prevButton; @@ -574,28 +546,20 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. prevButton.setScaleType(ImageView.ScaleType.CENTER); prevButton.setImageDrawable(Theme.createSimpleSelectorDrawable(context, R.drawable.pl_previous, Theme.getColor(Theme.key_player_button), Theme.getColor(Theme.key_player_buttonActive))); bottomView.addView(prevButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - prevButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MediaController.getInstance().playPreviousMessage(); - } - }); + prevButton.setOnClickListener(v -> MediaController.getInstance().playPreviousMessage()); buttons[2] = playButton = new ImageView(context); playButton.setScaleType(ImageView.ScaleType.CENTER); playButton.setImageDrawable(Theme.createSimpleSelectorDrawable(context, R.drawable.pl_play, Theme.getColor(Theme.key_player_button), Theme.getColor(Theme.key_player_buttonActive))); bottomView.addView(playButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - playButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (MediaController.getInstance().isDownloadingCurrentMessage()) { - return; - } - if (MediaController.getInstance().isMessagePaused()) { - MediaController.getInstance().playMessage(MediaController.getInstance().getPlayingMessageObject()); - } else { - MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject()); - } + playButton.setOnClickListener(v -> { + if (MediaController.getInstance().isDownloadingCurrentMessage()) { + return; + } + if (MediaController.getInstance().isMessagePaused()) { + MediaController.getInstance().playMessage(MediaController.getInstance().getPlayingMessageObject()); + } else { + MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject()); } }); @@ -604,23 +568,15 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. nextButton.setScaleType(ImageView.ScaleType.CENTER); nextButton.setImageDrawable(Theme.createSimpleSelectorDrawable(context, R.drawable.pl_next, Theme.getColor(Theme.key_player_button), Theme.getColor(Theme.key_player_buttonActive))); bottomView.addView(nextButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MediaController.getInstance().playNextMessage(); - } - }); + nextButton.setOnClickListener(v -> MediaController.getInstance().playNextMessage()); buttons[4] = repeatButton = new ImageView(context); repeatButton.setScaleType(ImageView.ScaleType.CENTER); repeatButton.setPadding(0, 0, AndroidUtilities.dp(8), 0); bottomView.addView(repeatButton, LayoutHelper.createFrame(50, 48, Gravity.LEFT | Gravity.TOP)); - repeatButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - SharedConfig.toggleRepeatMode(); - updateRepeatButton(); - } + repeatButton.setOnClickListener(v -> { + SharedConfig.toggleRepeatMode(); + updateRepeatButton(); }); listView = new RecyclerListView(context) { @@ -702,12 +658,9 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); listView.setAdapter(listAdapter = new ListAdapter(context)); listView.setGlowColor(Theme.getColor(Theme.key_dialogScrollGlow)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (view instanceof AudioPlayerCell) { - ((AudioPlayerCell) view).didPressedButton(); - } + listView.setOnItemClickListener((view, position) -> { + if (view instanceof AudioPlayerCell) { + ((AudioPlayerCell) view).didPressedButton(); } }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -777,40 +730,37 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(messageObject); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - if (dids.size() > 1 || dids.get(0) == UserConfig.getInstance(currentAccount).getClientUserId() || message != null) { - for (int a = 0; a < dids.size(); a++) { - long did = dids.get(a); - if (message != null) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(message.toString(), did, null, null, true, null, null, null); - } - SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessages, did); + fragment.setDelegate((fragment1, dids, message, param) -> { + if (dids.size() > 1 || dids.get(0) == UserConfig.getInstance(currentAccount).getClientUserId() || message != null) { + for (int a = 0; a < dids.size(); a++) { + long did = dids.get(a); + if (message != null) { + SendMessagesHelper.getInstance(currentAccount).sendMessage(message.toString(), did, null, null, true, null, null, null); + } + SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessages, did); + } + fragment1.finishFragment(); + } else { + long did = dids.get(0); + int lower_part = (int) did; + int high_part = (int) (did >> 32); + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + if (lower_part != 0) { + if (lower_part > 0) { + args1.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args1.putInt("chat_id", -lower_part); } - fragment.finishFragment(); } else { - long did = dids.get(0); - int lower_part = (int) did; - int high_part = (int) (did >> 32); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - if (lower_part != 0) { - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - args.putInt("chat_id", -lower_part); - } - } else { - args.putInt("enc_id", high_part); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - ChatActivity chatActivity = new ChatActivity(args); - if (parentActivity.presentFragment(chatActivity, true, false)) { - chatActivity.showFieldPanelForForward(true, fmessages); - } else { - fragment.finishFragment(); - } + args1.putInt("enc_id", high_part); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + ChatActivity chatActivity = new ChatActivity(args1); + if (parentActivity.presentFragment(chatActivity, true, false)) { + chatActivity.showFieldPanelForForward(true, fmessages); + } else { + fragment1.finishFragment(); } } }); @@ -892,34 +842,28 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - deleteForAll[0] = !deleteForAll[0]; - cell.setChecked(deleteForAll[0], true); - } + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + deleteForAll[0] = !deleteForAll[0]; + cell1.setChecked(deleteForAll[0], true); }); builder.setView(frameLayout); } } } } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dismiss(); - ArrayList arr = new ArrayList<>(); - arr.add(messageObject.getId()); - ArrayList random_ids = null; - TLRPC.EncryptedChat encryptedChat = null; - if ((int) messageObject.getDialogId() == 0 && messageObject.messageOwner.random_id != 0) { - random_ids = new ArrayList<>(); - random_ids.add(messageObject.messageOwner.random_id); - encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat((int) (messageObject.getDialogId() >> 32)); - } - MessagesController.getInstance(currentAccount).deleteMessages(arr, random_ids, encryptedChat, messageObject.messageOwner.to_id.channel_id, deleteForAll[0]); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + dismiss(); + ArrayList arr = new ArrayList<>(); + arr.add(messageObject.getId()); + ArrayList random_ids = null; + TLRPC.EncryptedChat encryptedChat = null; + if ((int) messageObject.getDialogId() == 0 && messageObject.messageOwner.random_id != 0) { + random_ids = new ArrayList<>(); + random_ids.add(messageObject.messageOwner.random_id); + encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat((int) (messageObject.getDialogId() >> 32)); } + MessagesController.getInstance(currentAccount).deleteMessages(arr, random_ids, encryptedChat, messageObject.messageOwner.to_id.channel_id, deleteForAll[0]); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.show(); @@ -1346,85 +1290,76 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - final ArrayList copy = new ArrayList<>(playlist); - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + AndroidUtilities.runOnUIThread(() -> { + final ArrayList copy = new ArrayList<>(playlist); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList resultArray = new ArrayList<>(); + ArrayList resultArray = new ArrayList<>(); - for (int a = 0; a < copy.size(); a++) { - MessageObject messageObject = copy.get(a); - for (int b = 0; b < search.length; b++) { - String q = search[b]; - String name = messageObject.getDocumentName(); - if (name == null || name.length() == 0) { - continue; + for (int a = 0; a < copy.size(); a++) { + MessageObject messageObject = copy.get(a); + for (int b = 0; b < search.length; b++) { + String q = search[b]; + String name = messageObject.getDocumentName(); + if (name == null || name.length() == 0) { + continue; + } + name = name.toLowerCase(); + if (name.contains(q)) { + resultArray.add(messageObject); + break; + } + TLRPC.Document document; + if (messageObject.type == 0) { + document = messageObject.messageOwner.media.webpage.document; + } else { + document = messageObject.messageOwner.media.document; + } + boolean ok = false; + for (int c = 0; c < document.attributes.size(); c++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(c); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.performer != null) { + ok = attribute.performer.toLowerCase().contains(q); } - name = name.toLowerCase(); - if (name.contains(q)) { - resultArray.add(messageObject); - break; - } - TLRPC.Document document; - if (messageObject.type == 0) { - document = messageObject.messageOwner.media.webpage.document; - } else { - document = messageObject.messageOwner.media.document; - } - boolean ok = false; - for (int c = 0; c < document.attributes.size(); c++) { - TLRPC.DocumentAttribute attribute = document.attributes.get(c); - if (attribute instanceof TLRPC.TL_documentAttributeAudio) { - if (attribute.performer != null) { - ok = attribute.performer.toLowerCase().contains(q); - } - if (!ok && attribute.title != null) { - ok = attribute.title.toLowerCase().contains(q); - } - break; - } - } - if (ok) { - resultArray.add(messageObject); - break; + if (!ok && attribute.title != null) { + ok = attribute.title.toLowerCase().contains(q); } + break; } } - - updateSearchResults(resultArray); + if (ok) { + resultArray.add(messageObject); + break; + } } - }); - } + } + + updateSearchResults(resultArray); + }); }); } private void updateSearchResults(final ArrayList documents) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchWas = true; - searchResult = documents; - notifyDataSetChanged(); - layoutManager.scrollToPosition(0); - } + AndroidUtilities.runOnUIThread(() -> { + searchWas = true; + searchResult = documents; + notifyDataSetChanged(); + layoutManager.scrollToPosition(0); }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BetterRatingView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BetterRatingView.java index 53c688aca..79bbb67c8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BetterRatingView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BetterRatingView.java @@ -16,59 +16,59 @@ import org.telegram.ui.ActionBar.Theme; * Created by grishka on 10.02.17. */ -public class BetterRatingView extends View{ +public class BetterRatingView extends View { private Bitmap filledStar, hollowStar; - private Paint paint=new Paint(); - private int numStars=5; - private int selectedRating=0; + private Paint paint = new Paint(); + private int numStars = 5; + private int selectedRating = 0; private OnRatingChangeListener listener; - public BetterRatingView(Context context){ + public BetterRatingView(Context context) { super(context); - filledStar=BitmapFactory.decodeResource(getResources(), R.drawable.ic_rating_star_filled).extractAlpha(); - hollowStar=BitmapFactory.decodeResource(getResources(), R.drawable.ic_rating_star).extractAlpha(); + filledStar = BitmapFactory.decodeResource(getResources(), R.drawable.ic_rating_star_filled).extractAlpha(); + hollowStar = BitmapFactory.decodeResource(getResources(), R.drawable.ic_rating_star).extractAlpha(); } @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ - setMeasuredDimension(numStars*AndroidUtilities.dp(32)+(numStars-1)*AndroidUtilities.dp(16), AndroidUtilities.dp(32)); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(numStars * AndroidUtilities.dp(32) + (numStars - 1) * AndroidUtilities.dp(16), AndroidUtilities.dp(32)); } @Override - protected void onDraw(Canvas canvas){ - for(int i=0;ioffset && event.getX() offset && event.getX() < offset + AndroidUtilities.dp(32 + 16)) { + if (selectedRating != i + 1) { + selectedRating = i + 1; + if (listener != null) listener.onRatingChanged(selectedRating); invalidate(); break; } } - offset+=AndroidUtilities.dp(32+16); + offset += AndroidUtilities.dp(32 + 16); } return true; } - public int getRating(){ + public int getRating() { return selectedRating; } - public void setOnRatingChangeListener(OnRatingChangeListener l){ - listener=l; + public void setOnRatingChangeListener(OnRatingChangeListener l) { + listener = l; } - public static interface OnRatingChangeListener{ - public void onRatingChanged(int newRating); + public interface OnRatingChangeListener { + void onRatingChanged(int newRating); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java index 48f10d677..ad3c33a63 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlockingUpdateView.java @@ -5,10 +5,8 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.StateListAnimator; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Canvas; import android.net.Uri; @@ -73,16 +71,12 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setPadding(0, 0, 0, AndroidUtilities.dp(14)); view.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, top, 0, 0)); - imageView.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - pressCount++; - if (pressCount >= 10) { - setVisibility(GONE); - UserConfig.getInstance(0).pendingAppUpdate = null; - UserConfig.getInstance(0).saveConfig(false); - } + imageView.setOnClickListener(v -> { + pressCount++; + if (pressCount >= 10) { + setVisibility(GONE); + UserConfig.getInstance(0).pendingAppUpdate = null; + UserConfig.getInstance(0).saveConfig(false); } }); @@ -120,20 +114,17 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente } acceptButton.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0); addView(acceptButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 56, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 45)); - acceptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (!checkApkInstallPermissions(getContext())) { - return; - } - if (appUpdate.document instanceof TLRPC.TL_document) { - if (!openApkInstall((Activity) getContext(), appUpdate.document)) { - FileLoader.getInstance(accountNum).loadFile(appUpdate.document, true, 1); - showProgress(true); - } - } else if (appUpdate.url != null) { - Browser.openUrl(getContext(), appUpdate.url); + acceptButton.setOnClickListener(view1 -> { + if (!checkApkInstallPermissions(getContext())) { + return; + } + if (appUpdate.document instanceof TLRPC.TL_document) { + if (!openApkInstall((Activity) getContext(), appUpdate.document)) { + FileLoader.getInstance(accountNum).loadFile(appUpdate.document, true, 1); + showProgress(true); } + } else if (appUpdate.url != null) { + Browser.openUrl(getContext(), appUpdate.url); } }); @@ -210,15 +201,11 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("ApkRestricted", R.string.ApkRestricted)); - builder.setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { - @TargetApi(Build.VERSION_CODES.O) - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - context.startActivity(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName()))); - } catch (Exception e) { - FileLog.e(e); - } + builder.setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { + try { + context.startActivity(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName()))); + } catch (Exception e) { + FileLog.e(e); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 762215009..8b3680377 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -13,11 +13,9 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.app.Activity; import android.content.ClipDescription; import android.content.Context; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Canvas; @@ -35,7 +33,6 @@ import android.os.PowerManager; import android.support.annotation.Keep; import android.support.v13.view.inputmethod.EditorInfoCompat; import android.support.v13.view.inputmethod.InputConnectionCompat; -import android.support.v13.view.inputmethod.InputContentInfoCompat; import android.support.v4.os.BuildCompat; import android.text.Editable; import android.text.InputFilter; @@ -125,13 +122,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe public SeekBarWaveformView(Context context) { super(context); seekBarWaveform = new SeekBarWaveform(context); - seekBarWaveform.setDelegate(new SeekBar.SeekBarDelegate() { - @Override - public void onSeekBarDrag(float progress) { - if (audioToSendMessageObject != null) { - audioToSendMessageObject.audioProgress = progress; - MediaController.getInstance().seekToProgress(audioToSendMessageObject, progress); - } + seekBarWaveform.setDelegate(progress -> { + if (audioToSendMessageObject != null) { + audioToSendMessageObject.audioProgress = progress; + MediaController.getInstance().seekToProgress(audioToSendMessageObject, progress); } }); } @@ -326,7 +320,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe emojiView.closeSearch(true); emojiView.hideSearchKeyboard(); } - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); } } } @@ -756,21 +750,18 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe // } setEmojiButtonImage(); frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | Gravity.LEFT, 3, 0, 0, 0)); - emojiButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (!isPopupShowing() || currentPopupContentType != 0) { - showPopup(1, 0); - emojiView.onOpen(messageEditText.length() > 0 && !messageEditText.getText().toString().startsWith("@gif")); - } else { - if (searchingStickers) { - searchingStickers = false; - emojiView.closeSearch(false); - messageEditText.requestFocus(); - } - openKeyboardInternal(); - removeGifFromInputField(); + emojiButton.setOnClickListener(view -> { + if (!isPopupShowing() || currentPopupContentType != 0) { + showPopup(1, 0); + emojiView.onOpen(messageEditText.length() > 0 && !messageEditText.getText().toString().startsWith("@gif")); + } else { + if (searchingStickers) { + searchingStickers = false; + emojiView.closeSearch(false); + messageEditText.requestFocus(); } + openKeyboardInternal(); + removeGifFromInputField(); } }); @@ -780,27 +771,24 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe final InputConnection ic = super.onCreateInputConnection(editorInfo); EditorInfoCompat.setContentMimeTypes(editorInfo, new String[]{"image/gif", "image/*", "image/jpg", "image/png"}); - final InputConnectionCompat.OnCommitContentListener callback = new InputConnectionCompat.OnCommitContentListener() { - @Override - public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts) { - if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { - try { - inputContentInfo.requestPermission(); - } catch (Exception e) { - return false; - } + final InputConnectionCompat.OnCommitContentListener callback = (inputContentInfo, flags, opts) -> { + if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { + try { + inputContentInfo.requestPermission(); + } catch (Exception e) { + return false; } - ClipDescription description = inputContentInfo.getDescription(); - if (description.hasMimeType("image/gif")) { - SendMessagesHelper.prepareSendingDocument(null, null, inputContentInfo.getContentUri(), "image/gif", dialog_id, replyingMessageObject, inputContentInfo, null); - } else { - SendMessagesHelper.prepareSendingPhoto(null, inputContentInfo.getContentUri(), dialog_id, replyingMessageObject, null, null, null, inputContentInfo, 0, null); - } - if (delegate != null) { - delegate.onMessageSend(null); - } - return true; } + ClipDescription description = inputContentInfo.getDescription(); + if (description.hasMimeType("image/gif")) { + SendMessagesHelper.prepareSendingDocument(null, null, inputContentInfo.getContentUri(), "image/gif", dialog_id, replyingMessageObject, inputContentInfo, null); + } else { + SendMessagesHelper.prepareSendingPhoto(null, inputContentInfo.getContentUri(), dialog_id, replyingMessageObject, null, null, null, inputContentInfo, 0, null); + } + if (delegate != null) { + delegate.onMessageSend(null); + } + return true; }; return InputConnectionCompat.createWrapper(ic, editorInfo, callback); } @@ -831,12 +819,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } } }; - messageEditText.setDelegate(new EditTextCaption.EditTextCaptionDelegate() { - @Override - public void onSpansChanged() { - if (delegate != null) { - delegate.onTextSpansChanged(messageEditText.getText()); - } + messageEditText.setDelegate(() -> { + if (delegate != null) { + delegate.onTextSpansChanged(messageEditText.getText()); } }); updateFieldHint(); @@ -986,34 +971,31 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe // botButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); // } attachLayout.addView(botButton, LayoutHelper.createLinear(48, 48)); - botButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (searchingStickers) { - searchingStickers = false; - emojiView.closeSearch(false); - messageEditText.requestFocus(); - } - if (botReplyMarkup != null) { - if (!isPopupShowing() || currentPopupContentType != 1) { - showPopup(1, 1); - SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); - preferences.edit().remove("hidekeyboard_" + dialog_id).commit(); - } else { - if (currentPopupContentType == 1 && botButtonsMessageObject != null) { - SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); - preferences.edit().putInt("hidekeyboard_" + dialog_id, botButtonsMessageObject.getId()).commit(); - } - openKeyboardInternal(); + botButton.setOnClickListener(v -> { + if (searchingStickers) { + searchingStickers = false; + emojiView.closeSearch(false); + messageEditText.requestFocus(); + } + if (botReplyMarkup != null) { + if (!isPopupShowing() || currentPopupContentType != 1) { + showPopup(1, 1); + SharedPreferences preferences1 = MessagesController.getMainSettings(currentAccount); + preferences1.edit().remove("hidekeyboard_" + dialog_id).commit(); + } else { + if (currentPopupContentType == 1 && botButtonsMessageObject != null) { + SharedPreferences preferences1 = MessagesController.getMainSettings(currentAccount); + preferences1.edit().putInt("hidekeyboard_" + dialog_id, botButtonsMessageObject.getId()).commit(); } - } else if (hasBotCommands) { - setFieldText("/"); - messageEditText.requestFocus(); - openKeyboard(); - } - if (stickersExpanded) { - setStickersExpanded(false, false); + openKeyboardInternal(); } + } else if (hasBotCommands) { + setFieldText("/"); + messageEditText.requestFocus(); + openKeyboard(); + } + if (stickersExpanded) { + setStickersExpanded(false, false, false); } }); @@ -1062,12 +1044,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe // attachButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); // } attachLayout.addView(attachButton, LayoutHelper.createLinear(48, 48)); - attachButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - delegate.didPressedAttachButton(); - } - }); + attachButton.setOnClickListener(v -> delegate.didPressedAttachButton()); } recordedAudioPanel = new FrameLayout(context); @@ -1083,24 +1060,21 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordDeleteImageView.setImageResource(R.drawable.ic_ab_delete); recordDeleteImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelVoiceDelete), PorterDuff.Mode.MULTIPLY)); recordedAudioPanel.addView(recordDeleteImageView, LayoutHelper.createFrame(48, 48)); - recordDeleteImageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (videoToSendMessageObject != null) { - CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2); - } else { - MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); - if (playing != null && playing == audioToSendMessageObject) { - MediaController.getInstance().cleanupPlayer(true, true); - } + recordDeleteImageView.setOnClickListener(v -> { + if (videoToSendMessageObject != null) { + CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); + delegate.needStartRecordVideo(2); + } else { + MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); + if (playing != null && playing == audioToSendMessageObject) { + MediaController.getInstance().cleanupPlayer(true, true); } - if (audioToSendPath != null) { - new File(audioToSendPath).delete(); - } - hideRecordedAudioPanel(); - checkSendButton(true); } + if (audioToSendPath != null) { + new File(audioToSendPath).delete(); + } + hideRecordedAudioPanel(); + checkSendButton(true); }); videoTimelineView = new VideoTimelineView(context); @@ -1151,19 +1125,16 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordedAudioPlayButton.setImageDrawable(playDrawable); recordedAudioPlayButton.setScaleType(ImageView.ScaleType.CENTER); recordedAudioPanel.addView(recordedAudioPlayButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.BOTTOM, 48, 0, 0, 0)); - recordedAudioPlayButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (audioToSend == null) { - return; - } - if (MediaController.getInstance().isPlayingMessage(audioToSendMessageObject) && !MediaController.getInstance().isMessagePaused()) { - MediaController.getInstance().pauseMessage(audioToSendMessageObject); - recordedAudioPlayButton.setImageDrawable(playDrawable); - } else { - recordedAudioPlayButton.setImageDrawable(pauseDrawable); - MediaController.getInstance().playMessage(audioToSendMessageObject); - } + recordedAudioPlayButton.setOnClickListener(v -> { + if (audioToSend == null) { + return; + } + if (MediaController.getInstance().isPlayingMessage(audioToSendMessageObject) && !MediaController.getInstance().isMessagePaused()) { + MediaController.getInstance().pauseMessage(audioToSendMessageObject); + recordedAudioPlayButton.setImageDrawable(playDrawable); + } else { + recordedAudioPlayButton.setImageDrawable(pauseDrawable); + MediaController.getInstance().playMessage(audioToSendMessageObject); } }); @@ -1176,12 +1147,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordPanel.setVisibility(GONE); recordPanel.setBackgroundColor(Theme.getColor(Theme.key_chat_messagePanelBackground)); frameLayout.addView(recordPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); - recordPanel.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + recordPanel.setOnTouchListener((v, event) -> true); slideText = new LinearLayout(context); slideText.setOrientation(LinearLayout.HORIZONTAL); @@ -1206,19 +1172,16 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordSendText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); recordSendText.setAlpha(0.0f); recordSendText.setPadding(AndroidUtilities.dp(36), 0, 0, 0); - recordSendText.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (hasRecordVideo && videoSendButton.getTag() != null) { - CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2); - } else { - delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0); - } - recordingAudioVideo = false; - updateRecordIntefrace(); + recordSendText.setOnClickListener(v -> { + if (hasRecordVideo && videoSendButton.getTag() != null) { + CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); + delegate.needStartRecordVideo(2); + } else { + delegate.needStartRecordAudio(0); + MediaController.getInstance().stopRecording(0); } + recordingAudioVideo = false; + updateRecordIntefrace(); }); recordPanel.addView(recordSendText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); @@ -1243,52 +1206,12 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe audioVideoButtonContainer.setBackgroundColor(Theme.getColor(Theme.key_chat_messagePanelBackground)); audioVideoButtonContainer.setSoundEffectsEnabled(false); sendButtonContainer.addView(audioVideoButtonContainer, LayoutHelper.createFrame(48, 48)); - audioVideoButtonContainer.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - if (recordCircle.isSendButtonVisible()) { - if (!hasRecordVideo || calledRecordRunnable) { - startedDraggingX = -1; - if (hasRecordVideo && videoSendButton.getTag() != null) { - delegate.needStartRecordVideo(1); - } else { - delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(1); - } - recordingAudioVideo = false; - updateRecordIntefrace(); - } - return false; - } - if (parentFragment != null) { - TLRPC.Chat chat = parentFragment.getCurrentChat(); - if (ChatObject.isChannel(chat)) { - if (chat.banned_rights != null && chat.banned_rights.send_media) { - delegate.needShowMediaBanHint(); - return false; - } - } - } - if (hasRecordVideo) { - calledRecordRunnable = false; - recordAudioVideoRunnableStarted = true; - AndroidUtilities.runOnUIThread(recordAudioVideoRunnable, 150); - } else { - recordAudioVideoRunnable.run(); - } - } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { - if (recordCircle.isSendButtonVisible() || recordedAudioPanel.getVisibility() == VISIBLE) { - return false; - } - if (recordAudioVideoRunnableStarted) { - AndroidUtilities.cancelRunOnUIThread(recordAudioVideoRunnable); - delegate.onSwitchRecordMode(videoSendButton.getTag() == null); - setRecordVideoButtonVisible(videoSendButton.getTag() == null, true); - } else if (!hasRecordVideo || calledRecordRunnable) { + audioVideoButtonContainer.setOnTouchListener((view, motionEvent) -> { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (recordCircle.isSendButtonVisible()) { + if (!hasRecordVideo || calledRecordRunnable) { startedDraggingX = -1; if (hasRecordVideo && videoSendButton.getTag() != null) { - CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); delegate.needStartRecordVideo(1); } else { delegate.needStartRecordAudio(0); @@ -1297,71 +1220,108 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe recordingAudioVideo = false; updateRecordIntefrace(); } - } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudioVideo) { - float x = motionEvent.getX(); - float y = motionEvent.getY(); - if (recordCircle.isSendButtonVisible()) { - return false; - } - if (recordCircle.setLockTranslation(y) == 2) { - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(ObjectAnimator.ofFloat(recordCircle, "lockAnimatedTranslation", recordCircle.startTranslation), - ObjectAnimator.ofFloat(slideText, "alpha", 0.0f), - ObjectAnimator.ofFloat(slideText, "translationY", AndroidUtilities.dp(20)), - ObjectAnimator.ofFloat(recordSendText, "alpha", 1.0f), - ObjectAnimator.ofFloat(recordSendText, "translationY", -AndroidUtilities.dp(20), 0)); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.setDuration(150); - animatorSet.start(); - return false; - } - if (x < -distCanMove) { - if (hasRecordVideo && videoSendButton.getTag() != null) { - CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2); - } else { - delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0); + return false; + } + if (parentFragment != null) { + TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (ChatObject.isChannel(chat)) { + if (chat.banned_rights != null && chat.banned_rights.send_media) { + delegate.needShowMediaBanHint(); + return false; } - recordingAudioVideo = false; - updateRecordIntefrace(); - } - - x = x + audioVideoButtonContainer.getX(); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText.getLayoutParams(); - if (startedDraggingX != -1) { - float dist = (x - startedDraggingX); - params.leftMargin = AndroidUtilities.dp(30) + (int) dist; - slideText.setLayoutParams(params); - float alpha = 1.0f + dist / distCanMove; - if (alpha > 1) { - alpha = 1; - } else if (alpha < 0) { - alpha = 0; - } - slideText.setAlpha(alpha); - } - if (x <= slideText.getX() + slideText.getWidth() + AndroidUtilities.dp(30)) { - if (startedDraggingX == -1) { - startedDraggingX = x; - distCanMove = (recordPanel.getMeasuredWidth() - slideText.getMeasuredWidth() - AndroidUtilities.dp(48)) / 2.0f; - if (distCanMove <= 0) { - distCanMove = AndroidUtilities.dp(80); - } else if (distCanMove > AndroidUtilities.dp(80)) { - distCanMove = AndroidUtilities.dp(80); - } - } - } - if (params.leftMargin > AndroidUtilities.dp(30)) { - params.leftMargin = AndroidUtilities.dp(30); - slideText.setLayoutParams(params); - slideText.setAlpha(1); - startedDraggingX = -1; } } - view.onTouchEvent(motionEvent); - return true; + if (hasRecordVideo) { + calledRecordRunnable = false; + recordAudioVideoRunnableStarted = true; + AndroidUtilities.runOnUIThread(recordAudioVideoRunnable, 150); + } else { + recordAudioVideoRunnable.run(); + } + } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { + if (recordCircle.isSendButtonVisible() || recordedAudioPanel.getVisibility() == VISIBLE) { + return false; + } + if (recordAudioVideoRunnableStarted) { + AndroidUtilities.cancelRunOnUIThread(recordAudioVideoRunnable); + delegate.onSwitchRecordMode(videoSendButton.getTag() == null); + setRecordVideoButtonVisible(videoSendButton.getTag() == null, true); + } else if (!hasRecordVideo || calledRecordRunnable) { + startedDraggingX = -1; + if (hasRecordVideo && videoSendButton.getTag() != null) { + CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); + delegate.needStartRecordVideo(1); + } else { + delegate.needStartRecordAudio(0); + MediaController.getInstance().stopRecording(1); + } + recordingAudioVideo = false; + updateRecordIntefrace(); + } + } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudioVideo) { + float x = motionEvent.getX(); + float y = motionEvent.getY(); + if (recordCircle.isSendButtonVisible()) { + return false; + } + if (recordCircle.setLockTranslation(y) == 2) { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(ObjectAnimator.ofFloat(recordCircle, "lockAnimatedTranslation", recordCircle.startTranslation), + ObjectAnimator.ofFloat(slideText, "alpha", 0.0f), + ObjectAnimator.ofFloat(slideText, "translationY", AndroidUtilities.dp(20)), + ObjectAnimator.ofFloat(recordSendText, "alpha", 1.0f), + ObjectAnimator.ofFloat(recordSendText, "translationY", -AndroidUtilities.dp(20), 0)); + animatorSet.setInterpolator(new DecelerateInterpolator()); + animatorSet.setDuration(150); + animatorSet.start(); + return false; + } + if (x < -distCanMove) { + if (hasRecordVideo && videoSendButton.getTag() != null) { + CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); + delegate.needStartRecordVideo(2); + } else { + delegate.needStartRecordAudio(0); + MediaController.getInstance().stopRecording(0); + } + recordingAudioVideo = false; + updateRecordIntefrace(); + } + + x = x + audioVideoButtonContainer.getX(); + LayoutParams params = (LayoutParams) slideText.getLayoutParams(); + if (startedDraggingX != -1) { + float dist = (x - startedDraggingX); + params.leftMargin = AndroidUtilities.dp(30) + (int) dist; + slideText.setLayoutParams(params); + float alpha = 1.0f + dist / distCanMove; + if (alpha > 1) { + alpha = 1; + } else if (alpha < 0) { + alpha = 0; + } + slideText.setAlpha(alpha); + } + if (x <= slideText.getX() + slideText.getWidth() + AndroidUtilities.dp(30)) { + if (startedDraggingX == -1) { + startedDraggingX = x; + distCanMove = (recordPanel.getMeasuredWidth() - slideText.getMeasuredWidth() - AndroidUtilities.dp(48)) / 2.0f; + if (distCanMove <= 0) { + distCanMove = AndroidUtilities.dp(80); + } else if (distCanMove > AndroidUtilities.dp(80)) { + distCanMove = AndroidUtilities.dp(80); + } + } + } + if (params.leftMargin > AndroidUtilities.dp(30)) { + params.leftMargin = AndroidUtilities.dp(30); + slideText.setLayoutParams(params); + slideText.setAlpha(1); + startedDraggingX = -1; + } } + view.onTouchEvent(motionEvent); + return true; }); audioSendButton = new ImageView(context); @@ -1394,16 +1354,13 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe cancelBotButton.setScaleY(0.1f); cancelBotButton.setAlpha(0.0f); sendButtonContainer.addView(cancelBotButton, LayoutHelper.createFrame(48, 48)); - cancelBotButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - String text = messageEditText.getText().toString(); - int idx = text.indexOf(' '); - if (idx == -1 || idx == text.length() - 1) { - setFieldText(""); - } else { - setFieldText(text.substring(0, idx + 1)); - } + cancelBotButton.setOnClickListener(view -> { + String text = messageEditText.getText().toString(); + int idx = text.indexOf(' '); + if (idx == -1 || idx == text.length() - 1) { + setFieldText(""); + } else { + setFieldText(text.substring(0, idx + 1)); } }); @@ -1417,12 +1374,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe sendButton.setScaleY(0.1f); sendButton.setAlpha(0.0f); sendButtonContainer.addView(sendButton, LayoutHelper.createFrame(48, 48)); - sendButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - sendMessage(); - } - }); + sendButton.setOnClickListener(view -> sendMessage()); expandStickersButton = new ImageView(context); expandStickersButton.setScaleType(ImageView.ScaleType.CENTER); @@ -1432,28 +1384,25 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe expandStickersButton.setScaleY(0.1f); expandStickersButton.setAlpha(0.0f); sendButtonContainer.addView(expandStickersButton, LayoutHelper.createFrame(48, 48)); - expandStickersButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (expandStickersButton.getVisibility() != VISIBLE || expandStickersButton.getAlpha() != 1.0f) { - return; - } - if (stickersExpanded) { - if (searchingStickers) { - searchingStickers = false; - emojiView.closeSearch(true); - emojiView.hideSearchKeyboard(); - } else if (!stickersDragging) { - if (emojiView != null) { - emojiView.showSearchField(false); - } - } + expandStickersButton.setOnClickListener(v -> { + if (expandStickersButton.getVisibility() != VISIBLE || expandStickersButton.getAlpha() != 1.0f) { + return; + } + if (stickersExpanded) { + if (searchingStickers) { + searchingStickers = false; + emojiView.closeSearch(true); + emojiView.hideSearchKeyboard(); } else if (!stickersDragging) { - emojiView.showSearchField(true); - } - if (!stickersDragging) { - setStickersExpanded(!stickersExpanded, true); + if (emojiView != null) { + emojiView.showSearchField(false); + } } + } else if (!stickersDragging) { + emojiView.showSearchField(true); + } + if (!stickersDragging) { + setStickersExpanded(!stickersExpanded, true, false); } }); @@ -1464,12 +1413,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe // if (Build.VERSION.SDK_INT >= 21) { // doneButtonContainer.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); // } - doneButtonContainer.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - doneEditingMessage(); - } - }); + doneButtonContainer.setOnClickListener(view -> doneEditingMessage()); doneButtonImage = new ImageView(context); doneButtonImage.setScaleType(ImageView.ScaleType.CENTER); @@ -1860,7 +1804,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe layoutParams.topMargin = AndroidUtilities.dp(2) + (show ? topView.getLayoutParams().height : 0); textFieldContainer.setLayoutParams(layoutParams); if (stickersExpanded) { - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); } } @@ -2134,12 +2078,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe showEditDoneProgress(true, true); CharSequence[] message = new CharSequence[]{messageEditText.getText()}; ArrayList entities = DataQuery.getInstance(currentAccount).getEntities(message); - editingMessageReqId = SendMessagesHelper.getInstance(currentAccount).editMessage(editingMessageObject, message[0].toString(), messageWebPageSearch, parentFragment, entities, new Runnable() { - @Override - public void run() { - editingMessageReqId = 0; - setEditingMessageObject(null, false); - } + editingMessageReqId = SendMessagesHelper.getInstance(currentAccount).editMessage(editingMessageObject, message[0].toString(), messageWebPageSearch, parentFragment, entities, () -> { + editingMessageReqId = 0; + setEditingMessageObject(null, false); }); } } @@ -2889,31 +2830,28 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } if (focus) { if (!searchingStickers && !messageEditText.isFocused()) { - messageEditText.postDelayed(new Runnable() { - @Override - public void run() { - boolean allowFocus; - if (AndroidUtilities.isTablet()) { - if (parentActivity instanceof LaunchActivity) { - LaunchActivity launchActivity = (LaunchActivity) parentActivity; - if (launchActivity != null) { - View layout = launchActivity.getLayersActionBarLayout(); - allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; - } else { - allowFocus = true; - } + messageEditText.postDelayed(() -> { + boolean allowFocus; + if (AndroidUtilities.isTablet()) { + if (parentActivity instanceof LaunchActivity) { + LaunchActivity launchActivity = (LaunchActivity) parentActivity; + if (launchActivity != null) { + View layout = launchActivity.getLayersActionBarLayout(); + allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; } else { allowFocus = true; } } else { allowFocus = true; } - if (allowFocus && messageEditText != null) { - try { - messageEditText.requestFocus(); - } catch (Exception e) { - FileLog.e(e); - } + } else { + allowFocus = true; + } + if (allowFocus && messageEditText != null) { + try { + messageEditText.requestFocus(); + } catch (Exception e) { + FileLog.e(e); } } }, 600); @@ -2987,22 +2925,19 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (botKeyboardView == null) { botKeyboardView = new BotKeyboardView(parentActivity); botKeyboardView.setVisibility(GONE); - botKeyboardView.setDelegate(new BotKeyboardView.BotKeyboardViewDelegate() { - @Override - public void didPressedButton(TLRPC.KeyboardButton button) { - MessageObject object = replyingMessageObject != null ? replyingMessageObject : ((int) dialog_id < 0 ? botButtonsMessageObject : null); - didPressedBotButton(button, object, replyingMessageObject != null ? replyingMessageObject : botButtonsMessageObject); - if (replyingMessageObject != null) { - openKeyboardInternal(); - setButtons(botMessageObject, false); - } else if (botButtonsMessageObject.messageOwner.reply_markup.single_use) { - openKeyboardInternal(); - SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); - preferences.edit().putInt("answered_" + dialog_id, botButtonsMessageObject.getId()).commit(); - } - if (delegate != null) { - delegate.onMessageSend(null); - } + botKeyboardView.setDelegate(button -> { + MessageObject object = replyingMessageObject != null ? replyingMessageObject : ((int) dialog_id < 0 ? botButtonsMessageObject : null); + didPressedBotButton(button, object, replyingMessageObject != null ? replyingMessageObject : botButtonsMessageObject); + if (replyingMessageObject != null) { + openKeyboardInternal(); + setButtons(botMessageObject, false); + } else if (botButtonsMessageObject.messageOwner.reply_markup.single_use) { + openKeyboardInternal(); + SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); + preferences.edit().putInt("answered_" + dialog_id, botButtonsMessageObject.getId()).commit(); + } + if (delegate != null) { + delegate.onMessageSend(null); } }); sizeNotifierLayout.addView(botKeyboardView); @@ -3049,17 +2984,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); builder.setMessage(LocaleController.getString("ShareYouLocationInfo", R.string.ShareYouLocationInfo)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - parentActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); - pendingMessageObject = messageObject; - pendingLocationButton = button; - return; - } - SendMessagesHelper.getInstance(currentAccount).sendCurrentLocation(messageObject, button); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + parentActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); + pendingMessageObject = messageObject; + pendingLocationButton = button; + return; } + SendMessagesHelper.getInstance(currentAccount).sendCurrentLocation(messageObject, button); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); parentFragment.showDialog(builder.create()); @@ -3084,46 +3016,43 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe args.putBoolean("onlySelect", true); args.putInt("dialogsType", 1); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - int uid = messageObject.messageOwner.from_id; - if (messageObject.messageOwner.via_bot_id != 0) { - uid = messageObject.messageOwner.via_bot_id; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); - if (user == null) { - fragment.finishFragment(); - return; - } - long did = dids.get(0); - DataQuery.getInstance(currentAccount).saveDraft(did, "@" + user.username + " " + button.query, null, null, true); - if (did != dialog_id) { - int lower_part = (int) did; - if (lower_part != 0) { - Bundle args = new Bundle(); - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - args.putInt("chat_id", -lower_part); - } - if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, fragment)) { - return; - } - ChatActivity chatActivity = new ChatActivity(args); - if (parentFragment.presentFragment(chatActivity, true)) { - if (!AndroidUtilities.isTablet()) { - parentFragment.removeSelfFromStack(); - } - } else { - fragment.finishFragment(); + fragment.setDelegate((fragment1, dids, message, param) -> { + int uid = messageObject.messageOwner.from_id; + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(uid); + if (user == null) { + fragment1.finishFragment(); + return; + } + long did = dids.get(0); + DataQuery.getInstance(currentAccount).saveDraft(did, "@" + user.username + " " + button.query, null, null, true); + if (did != dialog_id) { + int lower_part = (int) did; + if (lower_part != 0) { + Bundle args1 = new Bundle(); + if (lower_part > 0) { + args1.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args1.putInt("chat_id", -lower_part); + } + if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { + return; + } + ChatActivity chatActivity = new ChatActivity(args1); + if (parentFragment.presentFragment(chatActivity, true)) { + if (!AndroidUtilities.isTablet()) { + parentFragment.removeSelfFromStack(); } } else { - fragment.finishFragment(); + fragment1.finishFragment(); } } else { - fragment.finishFragment(); + fragment1.finishFragment(); } + } else { + fragment1.finishFragment(); } }); parentFragment.presentFragment(fragment); @@ -3183,7 +3112,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe emojiView.closeSearch(true, MessageObject.getStickerSetId(sticker)); emojiView.hideSearchKeyboard(); } - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); } ChatActivityEnterView.this.onStickerSelected(sticker); DataQuery.getInstance(currentAccount).addRecentSticker(DataQuery.TYPE_IMAGE, sticker, (int) (System.currentTimeMillis() / 1000), false); @@ -3202,7 +3131,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe @Override public void onGifSelected(TLRPC.Document gif) { if (stickersExpanded) { - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); } SendMessagesHelper.getInstance(currentAccount).sendSticker(gif, dialog_id, replyingMessageObject); DataQuery.getInstance(currentAccount).addRecentGif(gif, (int) (System.currentTimeMillis() / 1000)); @@ -3243,12 +3172,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("ClearRecentEmoji", R.string.ClearRecentEmoji)); - builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - emojiView.clearRecentEmoji(); - } - }); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), (dialogInterface, i) -> emojiView.clearRecentEmoji()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); parentFragment.showDialog(builder.create()); } @@ -3291,7 +3215,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe @Override public void onSearchOpenClose(boolean open) { searchingStickers = open; - setStickersExpanded(open, false); + setStickersExpanded(open, false, false); } @Override @@ -3333,13 +3257,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe @Override public void onDragEnd(float velocity) { - if (!allowDragging()) + if (!allowDragging()) { return; + } stickersDragging = false; if ((wasExpanded && velocity >= AndroidUtilities.dp(200)) || (!wasExpanded && velocity <= AndroidUtilities.dp(-200)) || (wasExpanded && stickersExpansionProgress <= 0.6f) || (!wasExpanded && stickersExpansionProgress >= 0.4f)) { - setStickersExpanded(!wasExpanded, true); + setStickersExpanded(!wasExpanded, true, true); } else { - setStickersExpanded(wasExpanded, true); + setStickersExpanded(wasExpanded, true, true); } } @@ -3349,7 +3274,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return; } stickersDragging = false; - setStickersExpanded(wasExpanded, true); + setStickersExpanded(wasExpanded, true, false); } @Override @@ -3381,7 +3306,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe emojiView.closeSearch(true); emojiView.hideSearchKeyboard(); } - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, dialog_id, replyingMessageObject); if (delegate != null) { delegate.onMessageSend(null); @@ -3474,7 +3399,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe checkSendButton(true); } if (stickersExpanded && show != 1) { - setStickersExpanded(false, false); + setStickersExpanded(false, false, false); } } @@ -3504,7 +3429,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe searchingStickers = false; emojiView.closeSearch(true); messageEditText.requestFocus(); - setStickersExpanded(false, true); + setStickersExpanded(false, true, false); } else { if (searchingStickers) { searchingStickers = false; @@ -3583,7 +3508,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (w != oldw && stickersExpanded) { searchingStickers = false; emojiView.closeSearch(false); - setStickersExpanded(false, false); + setStickersExpanded(false, false, false); } videoTimelineView.clearFrames(); } @@ -3848,8 +3773,8 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } } - private void setStickersExpanded(boolean expanded, boolean animated) { - if (emojiView == null || expanded && !emojiView.areThereAnyStickers() || stickersExpanded == expanded) { + private void setStickersExpanded(boolean expanded, boolean animated, boolean byDrag) { + if (emojiView == null || expanded && !emojiView.areThereAnyStickers() || !byDrag && stickersExpanded == expanded) { return; } stickersExpanded = expanded; @@ -3876,12 +3801,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe ); anims.setDuration(400); anims.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - ((ObjectAnimator) anims.getChildAnimations().get(0)).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - stickersExpansionProgress = getTranslationY() / (-(stickersExpandedHeight - origHeight)); - sizeNotifierLayout.invalidate(); - } + ((ObjectAnimator) anims.getChildAnimations().get(0)).addUpdateListener(animation -> { + stickersExpansionProgress = getTranslationY() / (-(stickersExpandedHeight - origHeight)); + sizeNotifierLayout.invalidate(); }); anims.addListener(new AnimatorListenerAdapter() { @Override @@ -3910,12 +3832,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe ); anims.setDuration(400); anims.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - ((ObjectAnimator) anims.getChildAnimations().get(0)).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - stickersExpansionProgress = getTranslationY() / (-(stickersExpandedHeight - origHeight)); - sizeNotifierLayout.invalidate(); - } + ((ObjectAnimator) anims.getChildAnimations().get(0)).addUpdateListener(animation -> { + stickersExpansionProgress = getTranslationY() / (-(stickersExpandedHeight - origHeight)); + sizeNotifierLayout.invalidate(); }); anims.addListener(new AnimatorListenerAdapter() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java index 11a0c57e0..4b2d7f0fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -15,7 +15,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -561,12 +560,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(currentUser.first_name, currentUser.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - DataQuery.getInstance(currentAccount).removeInline(currentUser.id); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> DataQuery.getInstance(currentAccount).removeInline(currentUser.id)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.show(); } @@ -880,37 +874,34 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N }; attachPhotoLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); attachPhotoRecyclerView.setLayoutManager(attachPhotoLayoutManager); - attachPhotoRecyclerView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (baseFragment == null || baseFragment.getParentActivity() == null) { + attachPhotoRecyclerView.setOnItemClickListener((view, position) -> { + if (baseFragment == null || baseFragment.getParentActivity() == null) { + return; + } + if (!deviceHasGoodCamera || position != 0) { + if (deviceHasGoodCamera) { + position--; + } + ArrayList arrayList = getAllPhotosArray(); + if (position < 0 || position >= arrayList.size()) { return; } - if (!deviceHasGoodCamera || position != 0) { - if (deviceHasGoodCamera) { - position--; - } - ArrayList arrayList = getAllPhotosArray(); - if (position < 0 || position >= arrayList.size()) { - return; - } - PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); - PhotoViewer.getInstance().setParentAlert(ChatAttachAlert.this); - PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); - ChatActivity chatActivity; - int type; - if (baseFragment instanceof ChatActivity) { - chatActivity = (ChatActivity) baseFragment; - type = 0; - } else { - type = 4; - chatActivity = null; - } - PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, type, photoViewerProvider, chatActivity); - AndroidUtilities.hideKeyboard(baseFragment.getFragmentView().findFocus()); + PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); + PhotoViewer.getInstance().setParentAlert(ChatAttachAlert.this); + PhotoViewer.getInstance().setMaxSelectedPhotos(maxSelectedPhotos); + ChatActivity chatActivity; + int type; + if (baseFragment instanceof ChatActivity) { + chatActivity = (ChatActivity) baseFragment; + type = 0; } else { - openCamera(true); + type = 4; + chatActivity = null; } + PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, type, photoViewerProvider, chatActivity); + AndroidUtilities.hideKeyboard(baseFragment.getFragmentView().findFocus()); + } else { + openCamera(true); } }); attachPhotoRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -976,15 +967,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else if (a == 4) { sendDocumentsButton = attachButton; } - attachButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (buttonPressed) { - return; - } - buttonPressed = true; - delegate.didPressedButton((Integer) v.getTag()); + attachButton.setOnClickListener(v -> { + if (buttonPressed) { + return; } + buttonPressed = true; + delegate.didPressedButton((Integer) v.getTag()); }); } @@ -1055,15 +1043,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N counterTextView.setCompoundDrawablePadding(AndroidUtilities.dp(4)); counterTextView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); container.addView(counterTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 38, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 100 + 16)); - counterTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (cameraView == null) { - return; - } - openPhotoViewer(null, false, false); - CameraController.getInstance().stopPreview(cameraView.getCameraSession()); + counterTextView.setOnClickListener(v -> { + if (cameraView == null) { + return; } + openPhotoViewer(null, false, false); + CameraController.getInstance().stopPreview(cameraView.getCameraSession()); }); shutterButton = new ShutterButton(context); @@ -1092,36 +1077,25 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N recordTime.setAlpha(1.0f); recordTime.setText(String.format("%02d:%02d", 0, 0)); videoRecordTime = 0; - videoRecordRunnable = new Runnable() { - @Override - public void run() { - if (videoRecordRunnable == null) { - return; - } - videoRecordTime++; - recordTime.setText(String.format("%02d:%02d", videoRecordTime / 60, videoRecordTime % 60)); - AndroidUtilities.runOnUIThread(videoRecordRunnable, 1000); + videoRecordRunnable = () -> { + if (videoRecordRunnable == null) { + return; } + videoRecordTime++; + recordTime.setText(String.format("%02d:%02d", videoRecordTime / 60, videoRecordTime % 60)); + AndroidUtilities.runOnUIThread(videoRecordRunnable, 1000); }; AndroidUtilities.lockOrientation(parentFragment.getParentActivity()); - CameraController.getInstance().recordVideo(cameraView.getCameraSession(), outputFile, new CameraController.VideoTakeCallback() { - @Override - public void onFinishVideoRecording(String thumbPath, long duration) { - if (outputFile == null || baseFragment == null) { - return; - } - mediaFromExternalCamera = false; - MediaController.PhotoEntry photoEntry = new MediaController.PhotoEntry(0, lastImageId--, 0, outputFile.getAbsolutePath(), 0, true); - photoEntry.duration = (int) duration; - photoEntry.thumbPath = thumbPath; - openPhotoViewer(photoEntry, false, false); + CameraController.getInstance().recordVideo(cameraView.getCameraSession(), outputFile, (thumbPath, duration) -> { + if (outputFile == null || baseFragment == null) { + return; } - }, new Runnable() { - @Override - public void run() { - AndroidUtilities.runOnUIThread(videoRecordRunnable, 1000); - } - }); + mediaFromExternalCamera = false; + MediaController.PhotoEntry photoEntry = new MediaController.PhotoEntry(0, lastImageId--, 0, outputFile.getAbsolutePath(), 0, true); + photoEntry.duration = (int) duration; + photoEntry.thumbPath = thumbPath; + openPhotoViewer(photoEntry, false, false); + }, () -> AndroidUtilities.runOnUIThread(videoRecordRunnable, 1000)); shutterButton.setState(ShutterButton.State.RECORDING, true); return true; } @@ -1154,34 +1128,31 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N final File cameraFile = AndroidUtilities.generatePicturePath(); final boolean sameTakePictureOrientation = cameraView.getCameraSession().isSameTakePictureOrientation(); cameraView.getCameraSession().setFlipFront(parentFragment instanceof ChatActivity); - takingPhoto = CameraController.getInstance().takePicture(cameraFile, cameraView.getCameraSession(), new Runnable() { - @Override - public void run() { - takingPhoto = false; - if (cameraFile == null || baseFragment == null) { - return; - } - int orientation = 0; - try { - ExifInterface ei = new ExifInterface(cameraFile.getAbsolutePath()); - int exif = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); - switch (exif) { - case ExifInterface.ORIENTATION_ROTATE_90: - orientation = 90; - break; - case ExifInterface.ORIENTATION_ROTATE_180: - orientation = 180; - break; - case ExifInterface.ORIENTATION_ROTATE_270: - orientation = 270; - break; - } - } catch (Exception e) { - FileLog.e(e); - } - mediaFromExternalCamera = false; - openPhotoViewer(new MediaController.PhotoEntry(0, lastImageId--, 0, cameraFile.getAbsolutePath(), orientation, false), sameTakePictureOrientation, false); + takingPhoto = CameraController.getInstance().takePicture(cameraFile, cameraView.getCameraSession(), () -> { + takingPhoto = false; + if (cameraFile == null || baseFragment == null) { + return; } + int orientation = 0; + try { + ExifInterface ei = new ExifInterface(cameraFile.getAbsolutePath()); + int exif = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + switch (exif) { + case ExifInterface.ORIENTATION_ROTATE_90: + orientation = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + orientation = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + orientation = 270; + break; + } + } catch (Exception e) { + FileLog.e(e); + } + mediaFromExternalCamera = false; + openPhotoViewer(new MediaController.PhotoEntry(0, lastImageId--, 0, cameraFile.getAbsolutePath(), orientation, false), sameTakePictureOrientation, false); }); } }); @@ -1189,24 +1160,21 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N switchCameraButton = new ImageView(context); switchCameraButton.setScaleType(ImageView.ScaleType.CENTER); cameraPanel.addView(switchCameraButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.CENTER_VERTICAL)); - switchCameraButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (takingPhoto || cameraView == null || !cameraView.isInitied()) { - return; - } - cameraInitied = false; - cameraView.switchCamera(); - ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 0.0f).setDuration(100); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - switchCameraButton.setImageResource(cameraView != null && cameraView.isFrontface() ? R.drawable.camera_revert1 : R.drawable.camera_revert2); - ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 1.0f).setDuration(100).start(); - } - }); - animator.start(); + switchCameraButton.setOnClickListener(v -> { + if (takingPhoto || cameraView == null || !cameraView.isInitied()) { + return; } + cameraInitied = false; + cameraView.switchCamera(); + ObjectAnimator animator = ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 0.0f).setDuration(100); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + switchCameraButton.setImageResource(cameraView != null && cameraView.isFrontface() ? R.drawable.camera_revert1 : R.drawable.camera_revert2); + ObjectAnimator.ofFloat(switchCameraButton, "scaleX", 1.0f).setDuration(100).start(); + } + }); + animator.start(); }); for (int a = 0; a < 2; a++) { @@ -1214,38 +1182,35 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N flashModeButton[a].setScaleType(ImageView.ScaleType.CENTER); flashModeButton[a].setVisibility(View.INVISIBLE); cameraPanel.addView(flashModeButton[a], LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - flashModeButton[a].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(final View currentImage) { - if (flashAnimationInProgress || cameraView == null || !cameraView.isInitied() || !cameraOpened) { - return; - } - String current = cameraView.getCameraSession().getCurrentFlashMode(); - String next = cameraView.getCameraSession().getNextFlashMode(); - if (current.equals(next)) { - return; - } - cameraView.getCameraSession().setCurrentFlashMode(next); - flashAnimationInProgress = true; - ImageView nextImage = flashModeButton[0] == currentImage ? flashModeButton[1] : flashModeButton[0]; - nextImage.setVisibility(View.VISIBLE); - setCameraFlashModeIcon(nextImage, next); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(currentImage, "translationY", 0, AndroidUtilities.dp(48)), - ObjectAnimator.ofFloat(nextImage, "translationY", -AndroidUtilities.dp(48), 0), - ObjectAnimator.ofFloat(currentImage, "alpha", 1.0f, 0.0f), - ObjectAnimator.ofFloat(nextImage, "alpha", 0.0f, 1.0f)); - animatorSet.setDuration(200); - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - flashAnimationInProgress = false; - currentImage.setVisibility(View.INVISIBLE); - } - }); - animatorSet.start(); + flashModeButton[a].setOnClickListener(currentImage -> { + if (flashAnimationInProgress || cameraView == null || !cameraView.isInitied() || !cameraOpened) { + return; } + String current = cameraView.getCameraSession().getCurrentFlashMode(); + String next = cameraView.getCameraSession().getNextFlashMode(); + if (current.equals(next)) { + return; + } + cameraView.getCameraSession().setCurrentFlashMode(next); + flashAnimationInProgress = true; + ImageView nextImage = flashModeButton[0] == currentImage ? flashModeButton[1] : flashModeButton[0]; + nextImage.setVisibility(View.VISIBLE); + setCameraFlashModeIcon(nextImage, next); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(currentImage, "translationY", 0, AndroidUtilities.dp(48)), + ObjectAnimator.ofFloat(nextImage, "translationY", -AndroidUtilities.dp(48), 0), + ObjectAnimator.ofFloat(currentImage, "alpha", 1.0f, 0.0f), + ObjectAnimator.ofFloat(nextImage, "alpha", 0.0f, 1.0f)); + animatorSet.setDuration(200); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + flashAnimationInProgress = false; + currentImage.setVisibility(View.INVISIBLE); + } + }); + animatorSet.start(); }); } @@ -1275,13 +1240,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } }; cameraPhotoRecyclerView.setLayoutManager(cameraPhotoLayoutManager); - cameraPhotoRecyclerView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @SuppressWarnings("unchecked") - @Override - public void onItemClick(View view, int position) { - if (view instanceof PhotoAttachPhotoCell) { - ((PhotoAttachPhotoCell) view).callDelegate(); - } + cameraPhotoRecyclerView.setOnItemClickListener((view, position) -> { + if (view instanceof PhotoAttachPhotoCell) { + ((PhotoAttachPhotoCell) view).callDelegate(); } }); } @@ -1380,12 +1341,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public boolean cancelButtonPressed() { if (cameraOpened && cameraView != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (cameraView != null && !isDismissed() && Build.VERSION.SDK_INT >= 21) { - cameraView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN); - } + AndroidUtilities.runOnUIThread(() -> { + if (cameraView != null && !isDismissed() && Build.VERSION.SDK_INT >= 21) { + cameraView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN); } }, 1000); CameraController.getInstance().startPreview(cameraView.getCameraSession()); @@ -2131,12 +2089,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N layoutParams.height = finalHeight; cameraView.setLayoutParams(layoutParams); final FrameLayout.LayoutParams layoutParamsFinal = layoutParams; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (cameraView != null) { - cameraView.setLayoutParams(layoutParamsFinal); - } + AndroidUtilities.runOnUIThread(() -> { + if (cameraView != null) { + cameraView.setLayoutParams(layoutParamsFinal); } }); } @@ -2148,12 +2103,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N layoutParams.height = finalHeight; cameraIcon.setLayoutParams(layoutParams); final FrameLayout.LayoutParams layoutParamsFinal = layoutParams; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (cameraIcon != null) { - cameraIcon.setLayoutParams(layoutParamsFinal); - } + AndroidUtilities.runOnUIThread(() -> { + if (cameraIcon != null) { + cameraIcon.setLayoutParams(layoutParamsFinal); } }); } @@ -2683,36 +2635,33 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public RecyclerListView.Holder createHolder() { PhotoAttachPhotoCell cell = new PhotoAttachPhotoCell(mContext); - cell.setDelegate(new PhotoAttachPhotoCell.PhotoAttachPhotoCellDelegate() { - @Override - public void onCheckClick(PhotoAttachPhotoCell v) { - if (!mediaEnabled) { - return; - } - int index = (Integer) v.getTag(); - MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); - boolean added = !selectedPhotos.containsKey(photoEntry.imageId); - if (added && maxSelectedPhotos >= 0 && selectedPhotos.size() >= maxSelectedPhotos) { - return; - } - int num = added ? selectedPhotosOrder.size() : -1; - if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { - v.setChecked(num, added, true); - } else { - v.setChecked(-1, added, true); - } - addToSelectedPhotos(photoEntry, index); - int updateIndex = index; - if (PhotoAttachAdapter.this == cameraAttachAdapter) { - if (photoAttachAdapter.needCamera && deviceHasGoodCamera) { - updateIndex++; - } - photoAttachAdapter.notifyItemChanged(updateIndex); - } else { - cameraAttachAdapter.notifyItemChanged(updateIndex); - } - updatePhotosButton(); + cell.setDelegate(v -> { + if (!mediaEnabled) { + return; } + int index = (Integer) v.getTag(); + MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); + boolean added = !selectedPhotos.containsKey(photoEntry.imageId); + if (added && maxSelectedPhotos >= 0 && selectedPhotos.size() >= maxSelectedPhotos) { + return; + } + int num = added ? selectedPhotosOrder.size() : -1; + if (baseFragment instanceof ChatActivity && maxSelectedPhotos < 0) { + v.setChecked(num, added, true); + } else { + v.setChecked(-1, added, true); + } + addToSelectedPhotos(photoEntry, index); + int updateIndex = index; + if (PhotoAttachAdapter.this == cameraAttachAdapter) { + if (photoAttachAdapter.needCamera && deviceHasGoodCamera) { + updateIndex++; + } + photoAttachAdapter.notifyItemChanged(updateIndex); + } else { + cameraAttachAdapter.notifyItemChanged(updateIndex); + } + updatePhotosButton(); }); return new RecyclerListView.Holder(cell); } @@ -2797,7 +2746,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } private void setUseRevealAnimation(boolean value) { - if (!value || value && Build.VERSION.SDK_INT >= 18 && !AndroidUtilities.isTablet() && Build.VERSION.SDK_INT < 26 && baseFragment instanceof ChatActivity) { + if (!value || value && Build.VERSION.SDK_INT >= 18 && !AndroidUtilities.isTablet() && (Build.VERSION.SDK_INT < 26 || Build.VERSION.SDK_INT >= 28) && baseFragment instanceof ChatActivity) { useRevealAnimation = value; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index d2aa1cb80..e318cbcc8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -14,7 +14,6 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.Gravity; -import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -81,44 +80,36 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent timeItem.setScaleType(ImageView.ScaleType.CENTER); timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); addView(timeItem); - timeItem.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - parentFragment.showDialog(AlertsCreator.createTTLAlert(getContext(), parentFragment.getCurrentEncryptedChat()).create()); - } - }); + timeItem.setOnClickListener(v -> parentFragment.showDialog(AlertsCreator.createTTLAlert(getContext(), parentFragment.getCurrentEncryptedChat()).create())); } if (parentFragment != null) { - setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - TLRPC.User user = parentFragment.getCurrentUser(); - TLRPC.Chat chat = parentFragment.getCurrentChat(); - if (user != null) { - Bundle args = new Bundle(); - if (UserObject.isUserSelf(user)) { - args.putLong("dialog_id", parentFragment.getDialogId()); - MediaActivity fragment = new MediaActivity(args, new int[]{-1, -1, -1, -1, -1}); - fragment.setChatInfo(parentFragment.getCurrentChatInfo()); - parentFragment.presentFragment(fragment); - } else { - args.putInt("user_id", user.id); - if (timeItem != null) { - args.putLong("dialog_id", parentFragment.getDialogId()); - } - ProfileActivity fragment = new ProfileActivity(args); - fragment.setPlayProfileAnimation(true); - parentFragment.presentFragment(fragment); - } - } else if (chat != null) { - Bundle args = new Bundle(); - args.putInt("chat_id", chat.id); - ProfileActivity fragment = new ProfileActivity(args); + setOnClickListener(v -> { + TLRPC.User user = parentFragment.getCurrentUser(); + TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (user != null) { + Bundle args = new Bundle(); + if (UserObject.isUserSelf(user)) { + args.putLong("dialog_id", parentFragment.getDialogId()); + MediaActivity fragment = new MediaActivity(args, new int[]{-1, -1, -1, -1, -1}); fragment.setChatInfo(parentFragment.getCurrentChatInfo()); + parentFragment.presentFragment(fragment); + } else { + args.putInt("user_id", user.id); + if (timeItem != null) { + args.putLong("dialog_id", parentFragment.getDialogId()); + } + ProfileActivity fragment = new ProfileActivity(args); fragment.setPlayProfileAnimation(true); parentFragment.presentFragment(fragment); } + } else if (chat != null) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat.id); + ProfileActivity fragment = new ProfileActivity(args); + fragment.setChatInfo(parentFragment.getCurrentChatInfo()); + fragment.setPlayProfileAnimation(true); + parentFragment.presentFragment(fragment); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java index d828acd61..f2af1423c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java @@ -111,8 +111,10 @@ public class EditTextBoldCursor extends EditText { try { gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[] {0xff54a1db, 0xff54a1db}); editor = mEditor.get(this); - mCursorDrawable = (Drawable[]) mCursorDrawableField.get(editor); - mCursorDrawableResField.set(this, R.drawable.field_carret_empty); + if (mCursorDrawableField != null) { + mCursorDrawable = (Drawable[]) mCursorDrawableField.get(editor); + mCursorDrawableResField.set(this, R.drawable.field_carret_empty); + } } catch (Exception e) { FileLog.e(e); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java index fd7b8ab37..d92ef9e06 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java @@ -11,7 +11,6 @@ package org.telegram.ui.Components; import android.content.Context; import android.util.TypedValue; import android.view.Gravity; -import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; @@ -44,12 +43,7 @@ public class EmptyTextProgressView extends FrameLayout { textView.setText(LocaleController.getString("NoResult", R.string.NoResult)); addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); - setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + setOnTouchListener((v, event) -> true); } public void showProgress() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java index 9cf622dfd..236f428e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -54,6 +54,8 @@ import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; +import com.google.android.exoplayer2.ExoPlayer; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.DispatchQueue; @@ -69,7 +71,6 @@ import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraInfo; import org.telegram.messenger.camera.CameraSession; import org.telegram.messenger.camera.Size; -import org.telegram.messenger.exoplayer2.ExoPlayer; import org.telegram.messenger.video.MP4Builder; import org.telegram.messenger.video.Mp4Movie; import org.telegram.tgnet.ConnectionsManager; @@ -1940,6 +1941,12 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter format.setInteger(MediaFormat.KEY_BIT_RATE, videoBitrate); format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL); + if (Build.VERSION.SDK_INT >= 21) { + format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); + if (Build.VERSION.SDK_INT >= 23) { + format.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel5); + } + } videoEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); surface = videoEncoder.createInputSurface(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java index 538341d10..5bbfc0ca8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java @@ -38,6 +38,8 @@ import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; @@ -46,7 +48,6 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.UserConfig; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.Theme; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoView.java index 2dd3ec7cb..0a9475016 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoView.java @@ -32,11 +32,12 @@ import android.webkit.WebView; import android.widget.FrameLayout; import android.widget.ImageView; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.PhotoViewer; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java index 382949585..2bdf8ac51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java @@ -125,11 +125,11 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { int r1 = Color.red(newColor); int g1 = Color.green(newColor); int b1 = Color.blue(newColor); - int a1 = Color.blue(newColor); + int a1 = Color.alpha(newColor); int r2 = Color.red(prevColor); int g2 = Color.green(prevColor); int b2 = Color.blue(prevColor); - int a2 = Color.blue(prevColor); + int a2 = Color.alpha(prevColor); prevTab.setTextColor(Color.argb((int) (a1 + (a2 - a1) * value), (int) (r1 + (r2 - r1) * value), (int) (g1 + (g2 - g1) * value), (int) (b1 + (b2 - b1) * value))); newTab.setTextColor(Color.argb((int) (a2 + (a1 - a2) * value), (int) (r2 + (r1 - r2) * value), (int) (g2 + (g1 - g2) * value), (int) (b2 + (b1 - b2) * value))); @@ -206,39 +206,36 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { tab.setSingleLine(true); tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); tab.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); - tab.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - int position = tabsContainer.indexOfChild(v); - if (position < 0 || position == currentPosition) { - return; - } - boolean scrollingForward = currentPosition < position; - previousPosition = currentPosition; - currentPosition = position; - selectedTabId = id; - - if (animatingIndicator) { - AndroidUtilities.cancelRunOnUIThread(animationRunnable); - animatingIndicator = false; - } - - animationTime = 0; - animatingIndicator = true; - animateIndicatorStartX = indicatorX; - animateIndicatorStartWidth = indicatorWidth; - - animateIndicatorToX = v.getLeft(); - animateIndicatorToWidth = v.getMeasuredWidth(); - setEnabled(false); - - AndroidUtilities.runOnUIThread(animationRunnable, 16); - - if (delegate != null) { - delegate.onPageSelected(id, scrollingForward); - } - scrollToChild(position); + tab.setOnClickListener(v -> { + int position1 = tabsContainer.indexOfChild(v); + if (position1 < 0 || position1 == currentPosition) { + return; } + boolean scrollingForward = currentPosition < position1; + previousPosition = currentPosition; + currentPosition = position1; + selectedTabId = id; + + if (animatingIndicator) { + AndroidUtilities.cancelRunOnUIThread(animationRunnable); + animatingIndicator = false; + } + + animationTime = 0; + animatingIndicator = true; + animateIndicatorStartX = indicatorX; + animateIndicatorStartWidth = indicatorWidth; + + animateIndicatorToX = v.getLeft(); + animateIndicatorToWidth = v.getMeasuredWidth(); + setEnabled(false); + + AndroidUtilities.runOnUIThread(animationRunnable, 16); + + if (delegate != null) { + delegate.onPageSelected(id, scrollingForward); + } + scrollToChild(position1); }); int tabWidth = (int) Math.ceil(tab.getPaint().measureText(text, 0, text.length())) + AndroidUtilities.dp(16); allTextWidth += tabWidth; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TextPaintImageReceiverSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TextPaintImageReceiverSpan.java new file mode 100644 index 000000000..a0433cb16 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TextPaintImageReceiverSpan.java @@ -0,0 +1,65 @@ +/* + * This is the source code of Telegram for Android v. 4.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-2018. + */ + +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.style.ReplacementSpan; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ImageReceiver; +import org.telegram.tgnet.TLRPC; + +import java.util.Locale; + +public class TextPaintImageReceiverSpan extends ReplacementSpan { + + public static final int ALIGN_BOTTOM = 0; + public static final int ALIGN_BASELINE = 1; + + protected final int mVerticalAlignment; + + private ImageReceiver imageReceiver; + private int width; + private int height; + + public TextPaintImageReceiverSpan(View parentView, TLRPC.Document document, int w, int h) { + mVerticalAlignment = ALIGN_BASELINE; + String filter = String.format(Locale.US, "%d_%d", w, h); + width = AndroidUtilities.dp(w); + height = AndroidUtilities.dp(h); + imageReceiver = new ImageReceiver(parentView); + imageReceiver.setImage(document, filter, document.thumb != null ? document.thumb.location : null, filter, -1, null, 1); + } + + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + if (fm != null) { + fm.ascent = -height; + fm.descent = 0; + + fm.top = fm.ascent; + fm.bottom = 0; + } + return width; + } + + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { + canvas.save(); + int transY = bottom - height; + if (mVerticalAlignment == ALIGN_BASELINE) { + transY -= paint.getFontMetricsInt().descent; + } + imageReceiver.setImageCoords((int) x, transY, width, height); + imageReceiver.draw(canvas); + canvas.restore(); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java index 47c8979fb..b271fc198 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java @@ -14,36 +14,37 @@ import android.net.Uri; import android.os.Handler; import android.view.TextureView; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.source.LoopingMediaSource; +import com.google.android.exoplayer2.DefaultLoadControl; +import com.google.android.exoplayer2.DefaultRenderersFactory; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerFactory; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; +import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.source.dash.DashMediaSource; +import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; +import com.google.android.exoplayer2.source.hls.HlsMediaSource; +import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource; +import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; +import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.MappingTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; + import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.exoplayer2.Player; -import org.telegram.messenger.exoplayer2.source.LoopingMediaSource; import org.telegram.messenger.secretmedia.ExtendedDefaultDataSourceFactory; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.exoplayer2.DefaultLoadControl; -import org.telegram.messenger.exoplayer2.DefaultRenderersFactory; -import org.telegram.messenger.exoplayer2.ExoPlaybackException; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ExoPlayerFactory; -import org.telegram.messenger.exoplayer2.PlaybackParameters; -import org.telegram.messenger.exoplayer2.SimpleExoPlayer; -import org.telegram.messenger.exoplayer2.Timeline; -import org.telegram.messenger.exoplayer2.extractor.DefaultExtractorsFactory; -import org.telegram.messenger.exoplayer2.source.ExtractorMediaSource; -import org.telegram.messenger.exoplayer2.source.MediaSource; -import org.telegram.messenger.exoplayer2.source.TrackGroupArray; -import org.telegram.messenger.exoplayer2.source.dash.DashMediaSource; -import org.telegram.messenger.exoplayer2.source.dash.DefaultDashChunkSource; -import org.telegram.messenger.exoplayer2.source.hls.HlsMediaSource; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.DefaultSsChunkSource; -import org.telegram.messenger.exoplayer2.source.smoothstreaming.SsMediaSource; -import org.telegram.messenger.exoplayer2.trackselection.AdaptiveTrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.DefaultTrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.MappingTrackSelector; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; -import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; -import org.telegram.messenger.exoplayer2.upstream.DataSource; -import org.telegram.messenger.exoplayer2.upstream.DefaultBandwidthMeter; -import org.telegram.messenger.exoplayer2.upstream.DefaultHttpDataSourceFactory; @SuppressLint("NewApi") public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.VideoListener, NotificationCenter.NotificationCenterDelegate { @@ -357,6 +358,11 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid } + @Override + public void onSurfaceSizeChanged(int width, int height) { + + } + public void setVolume(float volume) { if (player != null) { player.setVolume(volume); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java index 829f1578e..f9481ca9f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java @@ -9,7 +9,6 @@ package org.telegram.ui.Components; import android.app.Activity; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Point; @@ -58,42 +57,39 @@ public class WallpaperUpdater { } else { items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("Cancel", R.string.Cancel)}; } - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - if (i == 0) { - try { - Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - File image = AndroidUtilities.generatePicturePath(); - if (image != null) { - if (Build.VERSION.SDK_INT >= 24) { - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(parentActivity, BuildConfig.APPLICATION_ID + ".provider", image)); - takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } else { - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image)); - } - currentPicturePath = image.getAbsolutePath(); + builder.setItems(items, (dialogInterface, i) -> { + try { + if (i == 0) { + try { + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + File image = AndroidUtilities.generatePicturePath(); + if (image != null) { + if (Build.VERSION.SDK_INT >= 24) { + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(parentActivity, BuildConfig.APPLICATION_ID + ".provider", image)); + takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image)); } - parentActivity.startActivityForResult(takePictureIntent, 10); - } catch (Exception e) { - FileLog.e(e); - } - } else if (i == 1) { - Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); - photoPickerIntent.setType("image/*"); - parentActivity.startActivityForResult(photoPickerIntent, 11); - } else if (fromTheme) { - if (i == 2) { - delegate.needOpenColorPicker(); - } else if (i == 3) { - delegate.didSelectWallpaper(null, null); + currentPicturePath = image.getAbsolutePath(); } + parentActivity.startActivityForResult(takePictureIntent, 10); + } catch (Exception e) { + FileLog.e(e); + } + } else if (i == 1) { + Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); + photoPickerIntent.setType("image/*"); + parentActivity.startActivityForResult(photoPickerIntent, 11); + } else if (fromTheme) { + if (i == 2) { + delegate.needOpenColorPicker(); + } else if (i == 3) { + delegate.didSelectWallpaper(null, null); } - } catch (Exception e) { - FileLog.e(e); } + } catch (Exception e) { + FileLog.e(e); } }); builder.show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java index 31bd2fc27..823bab348 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebPlayerView.java @@ -36,12 +36,15 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.webkit.JavascriptInterface; -import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.FrameLayout; import android.widget.ImageView; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONTokener; @@ -54,9 +57,6 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -402,7 +402,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } } - private String extractFunction(String funcName) throws Exception { + private String extractFunction(String funcName) { try { String quote = Pattern.quote(funcName); Pattern funcPattern = Pattern.compile(String.format(Locale.US, "(?x)(?:function\\s+%s|[{;,]\\s*%s\\s*=\\s*function|var\\s+%s\\s*=\\s*function)\\s*\\(([^)]*)\\)\\s*\\{([^}]+)\\}", quote, quote, quote)); @@ -789,26 +789,20 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD } final String functionCodeFinal = functionCode; try { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (Build.VERSION.SDK_INT >= 21) { - webView.evaluateJavascript(functionCodeFinal, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - result[0] = result[0].replace(sig, "/signature/" + value.substring(1, value.length() - 1)); - countDownLatch.countDown(); - } - }); - } else { - try { - String javascript = ""; - byte[] data = javascript.getBytes("UTF-8"); - final String base64 = Base64.encodeToString(data, Base64.DEFAULT); - webView.loadUrl("data:text/html;charset=utf-8;base64," + base64); - } catch (Exception e) { - FileLog.e(e); - } + AndroidUtilities.runOnUIThread(() -> { + if (Build.VERSION.SDK_INT >= 21) { + webView.evaluateJavascript(functionCodeFinal, value -> { + result[0] = result[0].replace(sig, "/signature/" + value.substring(1, value.length() - 1)); + countDownLatch.countDown(); + }); + } else { + try { + String javascript = ""; + byte[] data = javascript.getBytes("UTF-8"); + final String base64 = Base64.encodeToString(data, Base64.DEFAULT); + webView.loadUrl("data:text/html;charset=utf-8;base64," + base64); + } catch (Exception e) { + FileLog.e(e); } } }); @@ -1185,12 +1179,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD currentBitmap = null; } } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - delegate.onInlineSurfaceTextureReady(); - } - }); + AndroidUtilities.runOnUIThread(() -> delegate.onInlineSurfaceTextureReady()); waitingForFirstTextureUpload = 0; return true; } @@ -1268,12 +1257,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD private AnimatorSet currentAnimation; private int lastProgressX; private int currentProgressX; - private Runnable hideRunnable = new Runnable() { - @Override - public void run() { - show(false, true); - } - }; + private Runnable hideRunnable = () -> show(false, true); public ControlsView(Context context) { super(context); @@ -1559,13 +1543,10 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD interfaceName = "JavaScriptInterface"; webView = new WebView(context); - webView.addJavascriptInterface(new JavaScriptInterface(new CallJavaResultInterface() { - @Override - public void jsCallFinished(String value) { - if (currentTask != null && !currentTask.isCancelled()) { - if (currentTask instanceof YoutubeVideoTask) { - ((YoutubeVideoTask) currentTask).onInterfaceResult(value); - } + webView.addJavascriptInterface(new JavaScriptInterface(value -> { + if (currentTask != null && !currentTask.isCancelled()) { + if (currentTask instanceof YoutubeVideoTask) { + ((YoutubeVideoTask) currentTask).onInterfaceResult(value); } } }), interfaceName); @@ -1611,96 +1592,87 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD fullscreenButton = new ImageView(context); fullscreenButton.setScaleType(ImageView.ScaleType.CENTER); controlsView.addView(fullscreenButton, LayoutHelper.createFrame(56, 56, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 0, 5)); - fullscreenButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (!initied || changingTextureView || switchingInlineMode || !firstFrameRendered) { - return; - } - inFullscreen = !inFullscreen; - updateFullscreenState(true); + fullscreenButton.setOnClickListener(v -> { + if (!initied || changingTextureView || switchingInlineMode || !firstFrameRendered) { + return; } + inFullscreen = !inFullscreen; + updateFullscreenState(true); }); playButton = new ImageView(context); playButton.setScaleType(ImageView.ScaleType.CENTER); controlsView.addView(playButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER)); - playButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (!initied || playVideoUrl == null) { - return; - } - if (!videoPlayer.isPlayerPrepared()) { - preparePlayer(); - } - if (videoPlayer.isPlaying()) { - videoPlayer.pause(); - } else { - isCompleted = false; - videoPlayer.play(); - } - updatePlayButton(); + playButton.setOnClickListener(v -> { + if (!initied || playVideoUrl == null) { + return; } + if (!videoPlayer.isPlayerPrepared()) { + preparePlayer(); + } + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + } else { + isCompleted = false; + videoPlayer.play(); + } + updatePlayButton(); }); if (allowInline) { inlineButton = new ImageView(context); inlineButton.setScaleType(ImageView.ScaleType.CENTER); controlsView.addView(inlineButton, LayoutHelper.createFrame(56, 48, Gravity.RIGHT | Gravity.TOP)); - inlineButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (textureView == null || !delegate.checkInlinePermissions() || changingTextureView || switchingInlineMode || !firstFrameRendered) { - return; + inlineButton.setOnClickListener(v -> { + if (textureView == null || !delegate.checkInlinePermissions() || changingTextureView || switchingInlineMode || !firstFrameRendered) { + return; + } + switchingInlineMode = true; + if (!isInline) { + inFullscreen = false; + delegate.prepareToSwitchInlineMode(true, switchToInlineRunnable, aspectRatioFrameLayout.getAspectRatio(), allowInlineAnimation); + } else { + ViewGroup parent = (ViewGroup) aspectRatioFrameLayout.getParent(); + if (parent != WebPlayerView.this) { + if (parent != null) { + parent.removeView(aspectRatioFrameLayout); + } + addView(aspectRatioFrameLayout, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); + aspectRatioFrameLayout.measure(MeasureSpec.makeMeasureSpec(WebPlayerView.this.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(WebPlayerView.this.getMeasuredHeight() - AndroidUtilities.dp(10), MeasureSpec.EXACTLY)); } - switchingInlineMode = true; - if (!isInline) { - inFullscreen = false; - delegate.prepareToSwitchInlineMode(true, switchToInlineRunnable, aspectRatioFrameLayout.getAspectRatio(), allowInlineAnimation); + if (currentBitmap != null) { + currentBitmap.recycle(); + currentBitmap = null; + } + changingTextureView = true; + + isInline = false; + updatePlayButton(); + updateShareButton(); + updateFullscreenButton(); + updateInlineButton(); + + textureView.setVisibility(INVISIBLE); + if (textureViewContainer != null) { + textureViewContainer.addView(textureView); } else { - ViewGroup parent = (ViewGroup) aspectRatioFrameLayout.getParent(); - if (parent != WebPlayerView.this) { - if (parent != null) { - parent.removeView(aspectRatioFrameLayout); - } - addView(aspectRatioFrameLayout, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); - aspectRatioFrameLayout.measure(MeasureSpec.makeMeasureSpec(WebPlayerView.this.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(WebPlayerView.this.getMeasuredHeight() - AndroidUtilities.dp(10), MeasureSpec.EXACTLY)); - } - if (currentBitmap != null) { - currentBitmap.recycle(); - currentBitmap = null; - } - changingTextureView = true; - - isInline = false; - updatePlayButton(); - updateShareButton(); - updateFullscreenButton(); - updateInlineButton(); - - textureView.setVisibility(INVISIBLE); - if (textureViewContainer != null) { - textureViewContainer.addView(textureView); - } else { - aspectRatioFrameLayout.addView(textureView); - } - - parent = (ViewGroup) controlsView.getParent(); - if (parent != WebPlayerView.this) { - if (parent != null) { - parent.removeView(controlsView); - } - if (textureViewContainer != null) { - textureViewContainer.addView(controlsView); - } else { - addView(controlsView, 1); - } - } - - controlsView.show(false, false); - delegate.prepareToSwitchInlineMode(false, null, aspectRatioFrameLayout.getAspectRatio(), allowInlineAnimation); + aspectRatioFrameLayout.addView(textureView); } + + parent = (ViewGroup) controlsView.getParent(); + if (parent != WebPlayerView.this) { + if (parent != null) { + parent.removeView(controlsView); + } + if (textureViewContainer != null) { + textureViewContainer.addView(controlsView); + } else { + addView(controlsView, 1); + } + } + + controlsView.show(false, false); + delegate.prepareToSwitchInlineMode(false, null, aspectRatioFrameLayout.getAspectRatio(), allowInlineAnimation); } }); } @@ -1710,12 +1682,9 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setImageResource(R.drawable.ic_share_video); controlsView.addView(shareButton, LayoutHelper.createFrame(56, 48, Gravity.RIGHT | Gravity.TOP)); - shareButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (delegate != null) { - delegate.onSharePressed(); - } + shareButton.setOnClickListener(v -> { + if (delegate != null) { + delegate.onSharePressed(); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java index 083de2500..98d9e3d33 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java @@ -23,6 +23,7 @@ import android.widget.Toast; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -38,8 +39,10 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.CheckBoxCell; +import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Components.BetterRatingView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.VoIPActivity; import java.io.File; @@ -214,7 +217,7 @@ public class VoIPHelper{ } public static void showRateAlert(final Context context, final Runnable onDismiss, final long callID, final long accessHash, final int account){ - final File log=new File(getLogsDir(), callID+".log"); + final File log=getLogFile(callID); LinearLayout alertView=new LinearLayout(context); alertView.setOrientation(LinearLayout.VERTICAL); @@ -311,6 +314,17 @@ public class VoIPHelper{ } }) .create(); + if(BuildVars.DEBUG_VERSION && log.exists()){ + alert.setNeutralButton("Send log", new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialog, int which){ + Intent intent=new Intent(context, LaunchActivity.class); + intent.setAction(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(log)); + context.startActivity(intent); + } + }); + } alert.setOnShowListener(new DialogInterface.OnShowListener(){ @Override public void onShow(DialogInterface dialog){ @@ -338,6 +352,19 @@ public class VoIPHelper{ }); } + private static File getLogFile(long callID){ + if(BuildVars.DEBUG_VERSION){ + File debugLogsDir=new File(ApplicationLoader.applicationContext.getExternalFilesDir(null), "logs"); + String[] logs=debugLogsDir.list(); + for(String log:logs){ + if(log.endsWith("voip"+callID+".txt")){ + return new File(debugLogsDir, log); + } + } + } + return new File(getLogsDir(), callID+".log"); + } + public static void upgradeP2pSetting(int account){ SharedPreferences prefs=MessagesController.getMainSettings(account); if(prefs.contains("calls_p2p")){ @@ -348,4 +375,67 @@ public class VoIPHelper{ e.remove("calls_p2p").commit(); } } + + public static void showCallDebugSettings(final Context context){ + final SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + LinearLayout ll=new LinearLayout(context); + ll.setOrientation(LinearLayout.VERTICAL); + + TextView warning=new TextView(context); + warning.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + warning.setText("Please only change these settings if you know exactly what they do."); + warning.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + ll.addView(warning, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 16, 8, 16, 8)); + + final TextCheckCell tcpCell=new TextCheckCell(context); + tcpCell.setTextAndCheck("Force TCP", preferences.getBoolean("dbg_force_tcp_in_calls", false), false); + tcpCell.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View v){ + boolean force= preferences.getBoolean("dbg_force_tcp_in_calls", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("dbg_force_tcp_in_calls", !force); + editor.commit(); + tcpCell.setChecked(!force); + } + }); + ll.addView(tcpCell); + + if(BuildVars.DEBUG_VERSION && BuildVars.LOGS_ENABLED){ + final TextCheckCell dumpCell=new TextCheckCell(context); + dumpCell.setTextAndCheck("Dump detailed stats", preferences.getBoolean("dbg_dump_call_stats", false), false); + dumpCell.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View v){ + boolean force= preferences.getBoolean("dbg_dump_call_stats", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("dbg_dump_call_stats", !force); + editor.commit(); + dumpCell.setChecked(!force); + } + }); + ll.addView(dumpCell); + } + + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ + final TextCheckCell connectionServiceCell=new TextCheckCell(context); + connectionServiceCell.setTextAndCheck("Enable ConnectionService", preferences.getBoolean("dbg_force_connection_service", false), false); + connectionServiceCell.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View v){ + boolean force= preferences.getBoolean("dbg_force_connection_service", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("dbg_force_connection_service", !force); + editor.commit(); + connectionServiceCell.setChecked(!force); + } + }); + ll.addView(connectionServiceCell); + } + + new AlertDialog.Builder(context) + .setTitle(LocaleController.getString("DebugMenuCallSettings", R.string.DebugMenuCallSettings)) + .setView(ll) + .show(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index d0f6db0fd..a3bb1cafe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -393,16 +393,13 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter builder.setMessage(LocaleController.getString("InviteUser", R.string.InviteUser)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); final String arg1 = usePhone; - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromParts("sms", arg1, null)); - intent.putExtra("sms_body", ContactsController.getInstance(currentAccount).getInviteText(1)); - getParentActivity().startActivityForResult(intent, 500); - } catch (Exception e) { - FileLog.e(e); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromParts("sms", arg1, null)); + intent.putExtra("sms_body", ContactsController.getInstance(currentAccount).getInviteText(1)); + getParentActivity().startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e(e); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java index 09334a895..4aa217ee3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java @@ -40,7 +40,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; @@ -152,27 +151,24 @@ public class CountrySelectActivity extends BaseFragment { listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - Country country; - if (searching && searchWas) { - country = searchListViewAdapter.getItem(position); - } else { - int section = listViewAdapter.getSectionForPosition(position); - int row = listViewAdapter.getPositionInSectionForPosition(position); - if (row < 0 || section < 0) { - return; - } - country = listViewAdapter.getItem(section, row); - } - if (position < 0) { + listView.setOnItemClickListener((view, position) -> { + Country country; + if (searching && searchWas) { + country = searchListViewAdapter.getItem(position); + } else { + int section = listViewAdapter.getSectionForPosition(position); + int row = listViewAdapter.getPositionInSectionForPosition(position); + if (row < 0 || section < 0) { return; } - finishFragment(); - if (country != null && delegate != null) { - delegate.didSelectCountry(country.name, country.shortname); - } + country = listViewAdapter.getItem(section, row); + } + if (position < 0) { + return; + } + finishFragment(); + if (country != null && delegate != null) { + delegate.didSelectCountry(country.name, country.shortname); } }); @@ -240,20 +236,10 @@ public class CountrySelectActivity extends BaseFragment { FileLog.e(e); } - Collections.sort(sortedCountries, new Comparator() { - @Override - public int compare(String lhs, String rhs) { - return lhs.compareTo(rhs); - } - }); + Collections.sort(sortedCountries, String::compareTo); for (ArrayList arr : countries.values()) { - Collections.sort(arr, new Comparator() { - @Override - public int compare(Country country, Country country2) { - return country.name.compareTo(country2.name); - } - }); + Collections.sort(arr, (country, country2) -> country.name.compareTo(country2.name)); } } @@ -390,39 +376,33 @@ public class CountrySelectActivity extends BaseFragment { } private void processSearch(final String query) { - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { + Utilities.searchQueue.postRunnable(() -> { - String q = query.trim().toLowerCase(); - if (q.length() == 0) { - updateSearchResults(new ArrayList()); - return; - } - ArrayList resultArray = new ArrayList<>(); + String q = query.trim().toLowerCase(); + if (q.length() == 0) { + updateSearchResults(new ArrayList<>()); + return; + } + ArrayList resultArray = new ArrayList<>(); - String n = query.substring(0, 1); - ArrayList arr = countries.get(n.toUpperCase()); - if (arr != null) { - for (Country c : arr) { - if (c.name.toLowerCase().startsWith(query)) { - resultArray.add(c); - } + String n = query.substring(0, 1); + ArrayList arr = countries.get(n.toUpperCase()); + if (arr != null) { + for (Country c : arr) { + if (c.name.toLowerCase().startsWith(query)) { + resultArray.add(c); } } - - updateSearchResults(resultArray); } + + updateSearchResults(resultArray); }); } private void updateSearchResults(final ArrayList arrCounties) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchResult = arrCounties; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + searchResult = arrCounties; + notifyDataSetChanged(); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index dd39aaee6..2933786b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -19,7 +19,6 @@ import android.annotation.TargetApi; import android.app.Activity; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -51,7 +50,6 @@ import org.telegram.messenger.DialogObject; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.support.widget.LinearLayoutManager; @@ -269,12 +267,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. searching = false; searchWas = false; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - Theme.createChatResources(context, false); - } - }); + AndroidUtilities.runOnUIThread(() -> Theme.createChatResources(context, false)); ActionBarMenu menu = actionBar.createMenu(); if (!onlySelect && searchString == null) { @@ -391,12 +384,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } actionBar.setSupportsHolidayImage(true); } - actionBar.setTitleActionRunnable(new Runnable() { - @Override - public void run() { - hideFloatingButton(false); - listView.smoothScrollToPosition(0); - } + actionBar.setTitleActionRunnable(() -> { + hideFloatingButton(false); + listView.smoothScrollToPosition(0); }); if (allowSwitchAccount && UserConfig.getActivatedAccountsCount() > 1) { @@ -619,149 +609,146 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. listView.setLayoutManager(layoutManager); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (listView == null || listView.getAdapter() == null || getParentActivity() == null) { - return; - } + listView.setOnItemClickListener((view, position) -> { + if (listView == null || listView.getAdapter() == null || getParentActivity() == null) { + return; + } - long dialog_id = 0; - int message_id = 0; - boolean isGlobalSearch = false; - RecyclerView.Adapter adapter = listView.getAdapter(); - if (adapter == dialogsAdapter) { - TLObject object = dialogsAdapter.getItem(position); - if (object instanceof TLRPC.User) { - dialog_id = ((TLRPC.User) object).id; - } else if (object instanceof TLRPC.TL_dialog) { - dialog_id = ((TLRPC.TL_dialog) object).id; - } else if (object instanceof TLRPC.TL_recentMeUrlChat) { - dialog_id = -((TLRPC.TL_recentMeUrlChat) object).chat_id; - } else if (object instanceof TLRPC.TL_recentMeUrlUser) { - dialog_id = ((TLRPC.TL_recentMeUrlUser) object).user_id; - } else if (object instanceof TLRPC.TL_recentMeUrlChatInvite) { - TLRPC.TL_recentMeUrlChatInvite chatInvite = (TLRPC.TL_recentMeUrlChatInvite) object; - TLRPC.ChatInvite invite = chatInvite.chat_invite; - if (invite.chat == null && (!invite.channel || invite.megagroup) || invite.chat != null && (!ChatObject.isChannel(invite.chat) || invite.chat.megagroup)) { - String hash = chatInvite.url; - int index = hash.indexOf('/'); - if (index > 0) { - hash = hash.substring(index + 1); - } - showDialog(new JoinGroupAlert(getParentActivity(), invite, hash, DialogsActivity.this)); + long dialog_id = 0; + int message_id = 0; + boolean isGlobalSearch = false; + RecyclerView.Adapter adapter = listView.getAdapter(); + if (adapter == dialogsAdapter) { + TLObject object = dialogsAdapter.getItem(position); + if (object instanceof TLRPC.User) { + dialog_id = ((TLRPC.User) object).id; + } else if (object instanceof TLRPC.TL_dialog) { + dialog_id = ((TLRPC.TL_dialog) object).id; + } else if (object instanceof TLRPC.TL_recentMeUrlChat) { + dialog_id = -((TLRPC.TL_recentMeUrlChat) object).chat_id; + } else if (object instanceof TLRPC.TL_recentMeUrlUser) { + dialog_id = ((TLRPC.TL_recentMeUrlUser) object).user_id; + } else if (object instanceof TLRPC.TL_recentMeUrlChatInvite) { + TLRPC.TL_recentMeUrlChatInvite chatInvite = (TLRPC.TL_recentMeUrlChatInvite) object; + TLRPC.ChatInvite invite = chatInvite.chat_invite; + if (invite.chat == null && (!invite.channel || invite.megagroup) || invite.chat != null && (!ChatObject.isChannel(invite.chat) || invite.chat.megagroup)) { + String hash = chatInvite.url; + int index = hash.indexOf('/'); + if (index > 0) { + hash = hash.substring(index + 1); + } + showDialog(new JoinGroupAlert(getParentActivity(), invite, hash, DialogsActivity.this)); + return; + } else { + if (invite.chat != null) { + dialog_id = -invite.chat.id; + } else { return; - } else { - if (invite.chat != null) { - dialog_id = -invite.chat.id; - } else { - return; - } } - } else if (object instanceof TLRPC.TL_recentMeUrlStickerSet) { - TLRPC.StickerSet stickerSet = ((TLRPC.TL_recentMeUrlStickerSet) object).set.set; - TLRPC.TL_inputStickerSetID set = new TLRPC.TL_inputStickerSetID(); - set.id = stickerSet.id; - set.access_hash = stickerSet.access_hash; - showDialog(new StickersAlert(getParentActivity(), DialogsActivity.this, set, null, null)); - return; - } else if (object instanceof TLRPC.TL_recentMeUrlUnknown) { - return; - } else { - return; } - } else if (adapter == dialogsSearchAdapter) { - Object obj = dialogsSearchAdapter.getItem(position); - isGlobalSearch = dialogsSearchAdapter.isGlobalSearch(position); - if (obj instanceof TLRPC.User) { - dialog_id = ((TLRPC.User) obj).id; - if (!onlySelect) { - dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.User) obj); - } - } else if (obj instanceof TLRPC.Chat) { - if (((TLRPC.Chat) obj).id > 0) { - dialog_id = -((TLRPC.Chat) obj).id; - } else { - dialog_id = AndroidUtilities.makeBroadcastId(((TLRPC.Chat) obj).id); - } - if (!onlySelect) { - dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.Chat) obj); - } - } else if (obj instanceof TLRPC.EncryptedChat) { - dialog_id = ((long) ((TLRPC.EncryptedChat) obj).id) << 32; - if (!onlySelect) { - dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.EncryptedChat) obj); - } - } else if (obj instanceof MessageObject) { - MessageObject messageObject = (MessageObject) obj; - dialog_id = messageObject.getDialogId(); - message_id = messageObject.getId(); - dialogsSearchAdapter.addHashtagsFromMessage(dialogsSearchAdapter.getLastSearchString()); - } else if (obj instanceof String) { - actionBar.openSearchField((String) obj); - } - } - - if (dialog_id == 0) { + } else if (object instanceof TLRPC.TL_recentMeUrlStickerSet) { + TLRPC.StickerSet stickerSet = ((TLRPC.TL_recentMeUrlStickerSet) object).set.set; + TLRPC.TL_inputStickerSetID set = new TLRPC.TL_inputStickerSetID(); + set.id = stickerSet.id; + set.access_hash = stickerSet.access_hash; + showDialog(new StickersAlert(getParentActivity(), DialogsActivity.this, set, null, null)); + return; + } else if (object instanceof TLRPC.TL_recentMeUrlUnknown) { + return; + } else { return; } - - if (onlySelect) { - if (dialogsAdapter.hasSelectedDialogs()) { - dialogsAdapter.addOrRemoveSelectedDialog(dialog_id, view); - updateSelectedCount(); + } else if (adapter == dialogsSearchAdapter) { + Object obj = dialogsSearchAdapter.getItem(position); + isGlobalSearch = dialogsSearchAdapter.isGlobalSearch(position); + if (obj instanceof TLRPC.User) { + dialog_id = ((TLRPC.User) obj).id; + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.User) obj); + } + } else if (obj instanceof TLRPC.Chat) { + if (((TLRPC.Chat) obj).id > 0) { + dialog_id = -((TLRPC.Chat) obj).id; } else { - didSelectResult(dialog_id, true, false); + dialog_id = AndroidUtilities.makeBroadcastId(((TLRPC.Chat) obj).id); + } + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.Chat) obj); + } + } else if (obj instanceof TLRPC.EncryptedChat) { + dialog_id = ((long) ((TLRPC.EncryptedChat) obj).id) << 32; + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.EncryptedChat) obj); + } + } else if (obj instanceof MessageObject) { + MessageObject messageObject = (MessageObject) obj; + dialog_id = messageObject.getDialogId(); + message_id = messageObject.getId(); + dialogsSearchAdapter.addHashtagsFromMessage(dialogsSearchAdapter.getLastSearchString()); + } else if (obj instanceof String) { + actionBar.openSearchField((String) obj); + } + } + + if (dialog_id == 0) { + return; + } + + if (onlySelect) { + if (dialogsAdapter.hasSelectedDialogs()) { + dialogsAdapter.addOrRemoveSelectedDialog(dialog_id, view); + updateSelectedCount(); + } else { + didSelectResult(dialog_id, true, false); + } + } else { + Bundle args = new Bundle(); + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_part != 0) { + if (high_id == 1) { + args.putInt("chat_id", lower_part); + } else { + if (lower_part > 0) { + args.putInt("user_id", lower_part); + } else if (lower_part < 0) { + if (message_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_part); + if (chat != null && chat.migrated_to != null) { + args.putInt("migrated_to", lower_part); + lower_part = -chat.migrated_to.channel_id; + } + } + args.putInt("chat_id", -lower_part); + } } } else { - Bundle args = new Bundle(); - int lower_part = (int) dialog_id; - int high_id = (int) (dialog_id >> 32); - if (lower_part != 0) { - if (high_id == 1) { - args.putInt("chat_id", lower_part); - } else { - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - if (message_id != 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_part); - if (chat != null && chat.migrated_to != null) { - args.putInt("migrated_to", lower_part); - lower_part = -chat.migrated_to.channel_id; - } - } - args.putInt("chat_id", -lower_part); - } - } - } else { - args.putInt("enc_id", high_id); + args.putInt("enc_id", high_id); + } + if (message_id != 0) { + args.putInt("message_id", message_id); + } else if (!isGlobalSearch) { + if (actionBar != null) { + actionBar.closeSearchField(); } - if (message_id != 0) { - args.putInt("message_id", message_id); - } else if (!isGlobalSearch) { - if (actionBar != null) { - actionBar.closeSearchField(); - } + } + if (AndroidUtilities.isTablet()) { + if (openedDialogId == dialog_id && adapter != dialogsSearchAdapter) { + return; } - if (AndroidUtilities.isTablet()) { - if (openedDialogId == dialog_id && adapter != dialogsSearchAdapter) { - return; - } - if (dialogsAdapter != null) { - dialogsAdapter.setOpenedDialogId(openedDialogId = dialog_id); - updateVisibleRows(MessagesController.UPDATE_MASK_SELECT_DIALOG); - } + if (dialogsAdapter != null) { + dialogsAdapter.setOpenedDialogId(openedDialogId = dialog_id); + updateVisibleRows(MessagesController.UPDATE_MASK_SELECT_DIALOG); } - if (searchString != null) { - if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, DialogsActivity.this)) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - presentFragment(new ChatActivity(args)); - } - } else { - if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, DialogsActivity.this)) { - presentFragment(new ChatActivity(args)); - } + } + if (searchString != null) { + if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, DialogsActivity.this)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + presentFragment(new ChatActivity(args)); + } + } else { + if (MessagesController.getInstance(currentAccount).checkCanOpenChat(args, DialogsActivity.this)) { + presentFragment(new ChatActivity(args)); } } } @@ -824,14 +811,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); - builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (dialogsSearchAdapter.isRecentSearchDisplayed()) { - dialogsSearchAdapter.clearRecentSearch(); - } else { - dialogsSearchAdapter.clearRecentHashtags(); - } + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), (dialogInterface, i) -> { + if (dialogsSearchAdapter.isRecentSearchDisplayed()) { + dialogsSearchAdapter.clearRecentSearch(); + } else { + dialogsSearchAdapter.clearRecentHashtags(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -890,63 +874,54 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. hasUnread ? LocaleController.getString("MarkAsRead", R.string.MarkAsRead) : LocaleController.getString("MarkAsUnread", R.string.MarkAsUnread), LocaleController.getString("LeaveChannelMenu", R.string.LeaveChannelMenu)}; } - builder.setItems(items, icons, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, final int which) { - if (which == 0) { - if (MessagesController.getInstance(currentAccount).pinDialog(selectedDialog, !pinned, null, 0) && !pinned) { - hideFloatingButton(false); - listView.smoothScrollToPosition(0); - } - } else if (which == 2) { - if (hasUnread) { - MessagesController.getInstance(currentAccount).markMentionsAsRead(selectedDialog); - MessagesController.getInstance(currentAccount).markDialogAsRead(selectedDialog, dialog.top_message, dialog.top_message, dialog.last_message_date, false, 0, true); - } else { - MessagesController.getInstance(currentAccount).markDialogAsUnread(selectedDialog, null, 0); - } - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (which == 1) { - if (chat != null && chat.megagroup) { - if (TextUtils.isEmpty(chat.username)) { - builder.setMessage(LocaleController.getString("AreYouSureClearHistory", R.string.AreYouSureClearHistory)); - } else { - builder.setMessage(LocaleController.getString("AreYouSureClearHistoryGroup", R.string.AreYouSureClearHistoryGroup)); - } - } else { - builder.setMessage(LocaleController.getString("AreYouSureClearHistoryChannel", R.string.AreYouSureClearHistoryChannel)); - } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (chat != null && chat.megagroup && TextUtils.isEmpty(chat.username)) { - MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 1); - } else { - MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 2); - } - } - }); - } else { - if (chat != null && chat.megagroup) { - builder.setMessage(LocaleController.getString("MegaLeaveAlert", R.string.MegaLeaveAlert)); - } else { - builder.setMessage(LocaleController.getString("ChannelLeaveAlert", R.string.ChannelLeaveAlert)); - } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -selectedDialog, UserConfig.getInstance(currentAccount).getCurrentUser(), null); - if (AndroidUtilities.isTablet()) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, selectedDialog); - } - } - }); - } - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + builder.setItems(items, icons, (d, which) -> { + if (which == 0) { + if (MessagesController.getInstance(currentAccount).pinDialog(selectedDialog, !pinned, null, 0) && !pinned) { + hideFloatingButton(false); + listView.smoothScrollToPosition(0); } + } else if (which == 2) { + if (hasUnread) { + MessagesController.getInstance(currentAccount).markMentionsAsRead(selectedDialog); + MessagesController.getInstance(currentAccount).markDialogAsRead(selectedDialog, dialog.top_message, dialog.top_message, dialog.last_message_date, false, 0, true); + } else { + MessagesController.getInstance(currentAccount).markDialogAsUnread(selectedDialog, null, 0); + } + } else { + AlertDialog.Builder builder1 = new AlertDialog.Builder(getParentActivity()); + builder1.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (which == 1) { + if (chat != null && chat.megagroup) { + if (TextUtils.isEmpty(chat.username)) { + builder1.setMessage(LocaleController.getString("AreYouSureClearHistory", R.string.AreYouSureClearHistory)); + } else { + builder1.setMessage(LocaleController.getString("AreYouSureClearHistoryGroup", R.string.AreYouSureClearHistoryGroup)); + } + } else { + builder1.setMessage(LocaleController.getString("AreYouSureClearHistoryChannel", R.string.AreYouSureClearHistoryChannel)); + } + builder1.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (chat != null && chat.megagroup && TextUtils.isEmpty(chat.username)) { + MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 1); + } else { + MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 2); + } + }); + } else { + if (chat != null && chat.megagroup) { + builder1.setMessage(LocaleController.getString("MegaLeaveAlert", R.string.MegaLeaveAlert)); + } else { + builder1.setMessage(LocaleController.getString("ChannelLeaveAlert", R.string.ChannelLeaveAlert)); + } + builder1.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -selectedDialog, UserConfig.getInstance(currentAccount).getCurrentUser(), null); + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, selectedDialog); + } + }); + } + builder1.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder1.create()); } }); showDialog(builder.create()); @@ -968,61 +943,55 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. R.drawable.chats_clear, hasUnread ? R.drawable.menu_read : R.drawable.menu_unread, isChat ? R.drawable.chats_leave : R.drawable.chats_delete - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, final int which) { - if (which == 0) { - if (MessagesController.getInstance(currentAccount).pinDialog(selectedDialog, !pinned, null, 0) && !pinned) { - hideFloatingButton(false); - listView.smoothScrollToPosition(0); - } - } else if (which == 2) { - if (hasUnread) { - MessagesController.getInstance(currentAccount).markMentionsAsRead(selectedDialog); - MessagesController.getInstance(currentAccount).markDialogAsRead(selectedDialog, dialog.top_message, dialog.top_message, dialog.last_message_date, false, 0, true); - } else { - MessagesController.getInstance(currentAccount).markDialogAsUnread(selectedDialog, null, 0); - } - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (which == 1) { - builder.setMessage(LocaleController.getString("AreYouSureClearHistory", R.string.AreYouSureClearHistory)); - } else { - if (isChat) { - builder.setMessage(LocaleController.getString("AreYouSureDeleteAndExit", R.string.AreYouSureDeleteAndExit)); - } else { - builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); - } - } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (which != 1) { - if (isChat) { - TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat((int) -selectedDialog); - if (currentChat != null && ChatObject.isNotInChat(currentChat)) { - MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 0); - } else { - MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -selectedDialog, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); - } - } else { - MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 0); - } - if (isBot) { - MessagesController.getInstance(currentAccount).blockUser((int) selectedDialog); - } - if (AndroidUtilities.isTablet()) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, selectedDialog); - } - } else { - MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 1); - } - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + }, (d, which) -> { + if (which == 0) { + if (MessagesController.getInstance(currentAccount).pinDialog(selectedDialog, !pinned, null, 0) && !pinned) { + hideFloatingButton(false); + listView.smoothScrollToPosition(0); } + } else if (which == 2) { + if (hasUnread) { + MessagesController.getInstance(currentAccount).markMentionsAsRead(selectedDialog); + MessagesController.getInstance(currentAccount).markDialogAsRead(selectedDialog, dialog.top_message, dialog.top_message, dialog.last_message_date, false, 0, true); + } else { + MessagesController.getInstance(currentAccount).markDialogAsUnread(selectedDialog, null, 0); + } + } else { + AlertDialog.Builder builder12 = new AlertDialog.Builder(getParentActivity()); + builder12.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (which == 1) { + builder12.setMessage(LocaleController.getString("AreYouSureClearHistory", R.string.AreYouSureClearHistory)); + } else { + if (isChat) { + builder12.setMessage(LocaleController.getString("AreYouSureDeleteAndExit", R.string.AreYouSureDeleteAndExit)); + } else { + builder12.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); + } + } + builder12.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (which != 1) { + if (isChat) { + TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat((int) -selectedDialog); + if (currentChat != null && ChatObject.isNotInChat(currentChat)) { + MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 0); + } else { + MessagesController.getInstance(currentAccount).deleteUserFromChat((int) -selectedDialog, MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()), null); + } + } else { + MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 0); + } + if (isBot) { + MessagesController.getInstance(currentAccount).blockUser((int) selectedDialog); + } + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, selectedDialog); + } + } else { + MessagesController.getInstance(currentAccount).deleteDialog(selectedDialog, 1); + } + }); + builder12.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder12.create()); } }); showDialog(builder.create()); @@ -1081,13 +1050,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }); } contentView.addView(floatingButton, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 14 : 0, 0, LocaleController.isRTL ? 0 : 14, 14)); - floatingButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Bundle args = new Bundle(); - args.putBoolean("destroyAfterSelect", true); - presentFragment(new ContactsActivity(args)); - } + floatingButton.setOnClickListener(v -> { + Bundle args = new Bundle(); + args.putBoolean("destroyAfterSelect", true); + presentFragment(new ContactsActivity(args)); }); unreadFloatingButtonContainer = new FrameLayout(context); @@ -1098,47 +1064,44 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. unreadFloatingButtonContainer.setTag(currentUnreadCount != 0 ? 1 : null); } contentView.addView(unreadFloatingButtonContainer, LayoutHelper.createFrame((Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 4 : 0, 0, LocaleController.isRTL ? 0 : 4, 14 + 60 + 7)); - unreadFloatingButtonContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (listView.getAdapter() == dialogsAdapter) { - int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); - if (firstVisibleItem == 0) { - ArrayList array = getDialogsArray(); - for (int a = array.size() - 1; a >= 0; a--) { - TLRPC.TL_dialog dialog = array.get(a); - if ((dialog.unread_count != 0 || dialog.unread_mark) && !MessagesController.getInstance(currentAccount).isDialogMuted(dialog.id)) { - listView.smoothScrollToPosition(a); + unreadFloatingButtonContainer.setOnClickListener(view -> { + if (listView.getAdapter() == dialogsAdapter) { + int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem == 0) { + ArrayList array = getDialogsArray(); + for (int a = array.size() - 1; a >= 0; a--) { + TLRPC.TL_dialog dialog = array.get(a); + if ((dialog.unread_count != 0 || dialog.unread_mark) && !MessagesController.getInstance(currentAccount).isDialogMuted(dialog.id)) { + listView.smoothScrollToPosition(a); + break; + } + } + } else { + int middle = listView.getMeasuredHeight() / 2; + boolean found = false; + for (int b = 0, count = listView.getChildCount(); b < count; b++) { + View child = listView.getChildAt(b); + if (child instanceof DialogCell) { + if (child.getTop() <= middle && child.getBottom() >= middle) { + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + if (holder != null) { + ArrayList array = getDialogsArray(); + for (int a = Math.min(holder.getAdapterPosition(), array.size()) - 1; a >= 0; a--) { + TLRPC.TL_dialog dialog = array.get(a); + if ((dialog.unread_count != 0 || dialog.unread_mark) && !MessagesController.getInstance(currentAccount).isDialogMuted(dialog.id)) { + found = true; + listView.smoothScrollToPosition(a); + break; + } + } + } break; } } - } else { - int middle = listView.getMeasuredHeight() / 2; - boolean found = false; - for (int b = 0, count = listView.getChildCount(); b < count; b++) { - View child = listView.getChildAt(b); - if (child instanceof DialogCell) { - if (child.getTop() <= middle && child.getBottom() >= middle) { - RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); - if (holder != null) { - ArrayList array = getDialogsArray(); - for (int a = Math.min(holder.getAdapterPosition(), array.size()) - 1; a >= 0; a--) { - TLRPC.TL_dialog dialog = array.get(a); - if ((dialog.unread_count != 0 || dialog.unread_mark) && !MessagesController.getInstance(currentAccount).isDialogMuted(dialog.id)) { - found = true; - listView.smoothScrollToPosition(a); - break; - } - } - } - break; - } - } - } - if (!found) { - hideFloatingButton(false); - listView.smoothScrollToPosition(0); - } + } + if (!found) { + hideFloatingButton(false); + listView.smoothScrollToPosition(0); } } } @@ -1340,12 +1303,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.formatString("ChatHintsDelete", R.string.ChatHintsDelete, ContactsController.formatName(user.first_name, user.last_name))); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - DataQuery.getInstance(currentAccount).removePeer(did); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> DataQuery.getInstance(currentAccount).removePeer(did)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } @@ -1499,13 +1457,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. checkPermission = false; if (activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { if (UserConfig.getInstance(currentAccount).syncContacts && activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) { - AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, new MessagesStorage.IntCallback() { - @Override - public void run(int param) { - askAboutContacts = param != 0; - MessagesController.getGlobalNotificationsSettings().edit().putBoolean("askAboutContacts", askAboutContacts).commit(); - askForPermissons(false); - } + AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, param -> { + askAboutContacts = param != 0; + MessagesController.getGlobalNotificationsSettings().edit().putBoolean("askAboutContacts", askAboutContacts).commit(); + askForPermissons(false); }); showDialog(permissionDialog = builder.create()); } else if (activity.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { @@ -1695,13 +1650,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ArrayList permissons = new ArrayList<>(); if (UserConfig.getInstance(currentAccount).syncContacts && askAboutContacts && activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (alert) { - AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, new MessagesStorage.IntCallback() { - @Override - public void run(int param) { - askAboutContacts = param != 0; - MessagesController.getGlobalNotificationsSettings().edit().putBoolean("askAboutContacts", askAboutContacts).commit(); - askForPermissons(false); - } + AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, param -> { + askAboutContacts = param != 0; + MessagesController.getGlobalNotificationsSettings().edit().putBoolean("askAboutContacts", askAboutContacts).commit(); + askForPermissons(false); }); showDialog(permissionDialog = builder.create()); return; @@ -2051,12 +2003,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. builder.setMessage(LocaleController.formatStringSimple(selectAlertString, UserObject.getUserName(user))); } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - didSelectResult(dialog_id, false, false); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> didSelectResult(dialog_id, false, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else { @@ -2073,29 +2020,26 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof ProfileSearchCell) { - ((ProfileSearchCell) child).update(0); - } else if (child instanceof DialogCell) { - ((DialogCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof ProfileSearchCell) { + ((ProfileSearchCell) child).update(0); + } else if (child instanceof DialogCell) { + ((DialogCell) child).update(0); } } - if (dialogsSearchAdapter != null) { - RecyclerListView recyclerListView = dialogsSearchAdapter.getInnerListView(); - if (recyclerListView != null) { - int count = recyclerListView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = recyclerListView.getChildAt(a); - if (child instanceof HintDialogCell) { - ((HintDialogCell) child).update(); - } + } + if (dialogsSearchAdapter != null) { + RecyclerListView recyclerListView = dialogsSearchAdapter.getInnerListView(); + if (recyclerListView != null) { + int count = recyclerListView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = recyclerListView.getChildAt(a); + if (child instanceof HintDialogCell) { + ((HintDialogCell) child).update(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java index 1108fcaeb..b2193af50 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java @@ -19,7 +19,6 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.os.Environment; import android.os.StatFs; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -53,7 +52,6 @@ import java.io.FileReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.StringTokenizer; @@ -105,17 +103,15 @@ public class DocumentSelectActivity extends BaseFragment { private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context arg0, Intent intent) { - Runnable r = new Runnable() { - public void run() { - try { - if (currentDir == null) { - listRoots(); - } else { - listFiles(currentDir); - } - } catch (Exception e) { - FileLog.e(e); + Runnable r = () -> { + try { + if (currentDir == null) { + listRoots(); + } else { + listFiles(currentDir); } + } catch (Exception e) { + FileLog.e(e); } }; if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { @@ -202,12 +198,7 @@ public class DocumentSelectActivity extends BaseFragment { selectedMessagesCountTextView.setTextSize(18); selectedMessagesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); selectedMessagesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); - selectedMessagesCountTextView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + selectedMessagesCountTextView.setOnTouchListener((v, event) -> true); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); actionModeViews.add(actionMode.addItemWithWidth(done, R.drawable.ic_ab_done, AndroidUtilities.dp(54))); @@ -232,143 +223,137 @@ public class DocumentSelectActivity extends BaseFragment { } }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (actionBar.isActionModeShowed()) { - return false; - } - ListItem item = listAdapter.getItem(position); - if (item == null) { - return false; - } - File file = item.file; - if (file != null && !file.isDirectory()) { - if (!file.canRead()) { - showErrorBox(LocaleController.getString("AccessError", R.string.AccessError)); - return false; - } - if (canSelectOnlyImageFiles && item.thumb == null) { - showErrorBox(LocaleController.formatString("PassportUploadNotImage", R.string.PassportUploadNotImage)); - return false; - } - if (sizeLimit != 0) { - if (file.length() > sizeLimit) { - showErrorBox(LocaleController.formatString("FileUploadLimit", R.string.FileUploadLimit, AndroidUtilities.formatFileSize(sizeLimit))); - return false; - } - } - if (maxSelectedFiles >= 0 && selectedFiles.size() >= maxSelectedFiles) { - showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); - return false; - } - if (file.length() == 0) { - return false; - } - selectedFiles.put(file.toString(), item); - selectedMessagesCountTextView.setNumber(1, false); - AnimatorSet animatorSet = new AnimatorSet(); - ArrayList animators = new ArrayList<>(); - for (int a = 0; a < actionModeViews.size(); a++) { - View view2 = actionModeViews.get(a); - AndroidUtilities.clearDrawableAnimation(view2); - animators.add(ObjectAnimator.ofFloat(view2, "scaleY", 0.1f, 1.0f)); - } - animatorSet.playTogether(animators); - animatorSet.setDuration(250); - animatorSet.start(); - scrolling = false; - if (view instanceof SharedDocumentCell) { - ((SharedDocumentCell) view).setChecked(true, true); - } - actionBar.showActionMode(); - } - return true; + listView.setOnItemLongClickListener((view, position) -> { + if (actionBar.isActionModeShowed()) { + return false; } + ListItem item = listAdapter.getItem(position); + if (item == null) { + return false; + } + File file = item.file; + if (file != null && !file.isDirectory()) { + if (!file.canRead()) { + showErrorBox(LocaleController.getString("AccessError", R.string.AccessError)); + return false; + } + if (canSelectOnlyImageFiles && item.thumb == null) { + showErrorBox(LocaleController.formatString("PassportUploadNotImage", R.string.PassportUploadNotImage)); + return false; + } + if (sizeLimit != 0) { + if (file.length() > sizeLimit) { + showErrorBox(LocaleController.formatString("FileUploadLimit", R.string.FileUploadLimit, AndroidUtilities.formatFileSize(sizeLimit))); + return false; + } + } + if (maxSelectedFiles >= 0 && selectedFiles.size() >= maxSelectedFiles) { + showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); + return false; + } + if (file.length() == 0) { + return false; + } + selectedFiles.put(file.toString(), item); + selectedMessagesCountTextView.setNumber(1, false); + AnimatorSet animatorSet = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); + for (int a = 0; a < actionModeViews.size(); a++) { + View view2 = actionModeViews.get(a); + AndroidUtilities.clearDrawableAnimation(view2); + animators.add(ObjectAnimator.ofFloat(view2, "scaleY", 0.1f, 1.0f)); + } + animatorSet.playTogether(animators); + animatorSet.setDuration(250); + animatorSet.start(); + scrolling = false; + if (view instanceof SharedDocumentCell) { + ((SharedDocumentCell) view).setChecked(true, true); + } + actionBar.showActionMode(); + } + return true; }); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - ListItem item = listAdapter.getItem(position); - if (item == null) { + listView.setOnItemClickListener((view, position) -> { + ListItem item = listAdapter.getItem(position); + if (item == null) { + return; + } + File file = item.file; + if (file == null) { + if (item.icon == R.drawable.ic_storage_gallery) { + if (delegate != null) { + delegate.startDocumentSelectActivity(); + } + finishFragment(false); + } else { + HistoryEntry he = history.remove(history.size() - 1); + actionBar.setTitle(he.title); + if (he.dir != null) { + listFiles(he.dir); + } else { + listRoots(); + } + layoutManager.scrollToPositionWithOffset(he.scrollItem, he.scrollOffset); + } + } else if (file.isDirectory()) { + HistoryEntry he = new HistoryEntry(); + he.scrollItem = layoutManager.findLastVisibleItemPosition(); + View topView = layoutManager.findViewByPosition(he.scrollItem); + if (topView != null) { + he.scrollOffset = topView.getTop(); + } + he.dir = currentDir; + he.title = actionBar.getTitle(); + history.add(he); + if (!listFiles(file)) { + history.remove(he); return; } - File file = item.file; - if (file == null) { - if (item.icon == R.drawable.ic_storage_gallery) { - if (delegate != null) { - delegate.startDocumentSelectActivity(); - } - finishFragment(false); + actionBar.setTitle(item.title); + } else { + if (!file.canRead()) { + showErrorBox(LocaleController.getString("AccessError", R.string.AccessError)); + file = new File("/mnt/sdcard"); + } + if (canSelectOnlyImageFiles && item.thumb == null) { + showErrorBox(LocaleController.formatString("PassportUploadNotImage", R.string.PassportUploadNotImage)); + return; + } + if (sizeLimit != 0) { + if (file.length() > sizeLimit) { + showErrorBox(LocaleController.formatString("FileUploadLimit", R.string.FileUploadLimit, AndroidUtilities.formatFileSize(sizeLimit))); + return; + } + } + if (file.length() == 0) { + return; + } + if (actionBar.isActionModeShowed()) { + if (selectedFiles.containsKey(file.toString())) { + selectedFiles.remove(file.toString()); } else { - HistoryEntry he = history.remove(history.size() - 1); - actionBar.setTitle(he.title); - if (he.dir != null) { - listFiles(he.dir); - } else { - listRoots(); - } - layoutManager.scrollToPositionWithOffset(he.scrollItem, he.scrollOffset); - } - } else if (file.isDirectory()) { - HistoryEntry he = new HistoryEntry(); - he.scrollItem = layoutManager.findLastVisibleItemPosition(); - View topView = layoutManager.findViewByPosition(he.scrollItem); - if (topView != null) { - he.scrollOffset = topView.getTop(); - } - he.dir = currentDir; - he.title = actionBar.getTitle(); - history.add(he); - if (!listFiles(file)) { - history.remove(he); - return; - } - actionBar.setTitle(item.title); - } else { - if (!file.canRead()) { - showErrorBox(LocaleController.getString("AccessError", R.string.AccessError)); - file = new File("/mnt/sdcard"); - } - if (canSelectOnlyImageFiles && item.thumb == null) { - showErrorBox(LocaleController.formatString("PassportUploadNotImage", R.string.PassportUploadNotImage)); - return; - } - if (sizeLimit != 0) { - if (file.length() > sizeLimit) { - showErrorBox(LocaleController.formatString("FileUploadLimit", R.string.FileUploadLimit, AndroidUtilities.formatFileSize(sizeLimit))); + if (maxSelectedFiles >= 0 && selectedFiles.size() >= maxSelectedFiles) { + showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); return; } + selectedFiles.put(file.toString(), item); } - if (file.length() == 0) { - return; - } - if (actionBar.isActionModeShowed()) { - if (selectedFiles.containsKey(file.toString())) { - selectedFiles.remove(file.toString()); - } else { - if (maxSelectedFiles >= 0 && selectedFiles.size() >= maxSelectedFiles) { - showErrorBox(LocaleController.formatString("PassportUploadMaxReached", R.string.PassportUploadMaxReached, LocaleController.formatPluralString("Files", maxSelectedFiles))); - return; - } - selectedFiles.put(file.toString(), item); - } - if (selectedFiles.isEmpty()) { - actionBar.hideActionMode(); - } else { - selectedMessagesCountTextView.setNumber(selectedFiles.size(), true); - } - scrolling = false; - if (view instanceof SharedDocumentCell) { - ((SharedDocumentCell) view).setChecked(selectedFiles.containsKey(item.file.toString()), true); - } + if (selectedFiles.isEmpty()) { + actionBar.hideActionMode(); } else { - if (delegate != null) { - ArrayList files = new ArrayList<>(); - files.add(file.getAbsolutePath()); - delegate.didSelectFiles(DocumentSelectActivity.this, files); - } + selectedMessagesCountTextView.setNumber(selectedFiles.size(), true); + } + scrolling = false; + if (view instanceof SharedDocumentCell) { + ((SharedDocumentCell) view).setChecked(selectedFiles.containsKey(item.file.toString()), true); + } + } else { + if (delegate != null) { + ArrayList files = new ArrayList<>(); + files.add(file.getAbsolutePath()); + delegate.didSelectFiles(DocumentSelectActivity.this, files); } } } @@ -408,18 +393,15 @@ public class DocumentSelectActivity extends BaseFragment { } recentItems.add(item); } - Collections.sort(recentItems, new Comparator() { - @Override - public int compare(ListItem o1, ListItem o2) { - long lm = o1.file.lastModified(); - long rm = o2.file.lastModified(); - if (lm == rm) { - return 0; - } else if (lm > rm) { - return -1; - } else { - return 1; - } + Collections.sort(recentItems, (o1, o2) -> { + long lm = o1.file.lastModified(); + long rm = o2.file.lastModified(); + if (lm == rm) { + return 0; + } else if (lm > rm) { + return -1; + } else { + return 1; } }); } catch (Exception e) { @@ -520,23 +502,20 @@ public class DocumentSelectActivity extends BaseFragment { } currentDir = dir; items.clear(); - Arrays.sort(files, new Comparator() { - @Override - public int compare(File lhs, File rhs) { - if (lhs.isDirectory() != rhs.isDirectory()) { - return lhs.isDirectory() ? -1 : 1; - } - return lhs.getName().compareToIgnoreCase(rhs.getName()); - /*long lm = lhs.lastModified(); - long rm = lhs.lastModified(); - if (lm == rm) { - return 0; - } else if (lm > rm) { - return -1; - } else { - return 1; - }*/ + Arrays.sort(files, (lhs, rhs) -> { + if (lhs.isDirectory() != rhs.isDirectory()) { + return lhs.isDirectory() ? -1 : 1; } + return lhs.getName().compareToIgnoreCase(rhs.getName()); + /*long lm = lhs.lastModified(); + long rm = lhs.lastModified(); + if (lm == rm) { + return 0; + } else if (lm > rm) { + return -1; + } else { + return 1; + }*/ }); for (int a = 0; a < files.length; a++) { File file = files[a]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java index 48fe2ad85..c9fa9ed1a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.app.Activity; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Shader; @@ -37,8 +36,6 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBarLayout; import org.telegram.ui.ActionBar.AlertDialog; @@ -126,39 +123,33 @@ public class ExternalActionActivity extends Activity implements ActionBarLayout. FrameLayout shadowTablet = new FrameLayout(this); shadowTablet.setBackgroundColor(0x7F000000); launchLayout.addView(shadowTablet, LayoutHelper.createRelative(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - shadowTablet.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (!actionBarLayout.fragmentsStack.isEmpty() && event.getAction() == MotionEvent.ACTION_UP) { - float x = event.getX(); - float y = event.getY(); - int location[] = new int[2]; - layersActionBarLayout.getLocationOnScreen(location); - int viewX = location[0]; - int viewY = location[1]; + shadowTablet.setOnTouchListener((v, event) -> { + if (!actionBarLayout.fragmentsStack.isEmpty() && event.getAction() == MotionEvent.ACTION_UP) { + float x = event.getX(); + float y = event.getY(); + int location[] = new int[2]; + layersActionBarLayout.getLocationOnScreen(location); + int viewX = location[0]; + int viewY = location[1]; - if (layersActionBarLayout.checkTransitionAnimation() || x > viewX && x < viewX + layersActionBarLayout.getWidth() && y > viewY && y < viewY + layersActionBarLayout.getHeight()) { - return false; - } else { - if (!layersActionBarLayout.fragmentsStack.isEmpty()) { - for (int a = 0; a < layersActionBarLayout.fragmentsStack.size() - 1; a++) { - layersActionBarLayout.removeFragmentFromStack(layersActionBarLayout.fragmentsStack.get(0)); - a--; - } - layersActionBarLayout.closeLastFragment(true); + if (layersActionBarLayout.checkTransitionAnimation() || x > viewX && x < viewX + layersActionBarLayout.getWidth() && y > viewY && y < viewY + layersActionBarLayout.getHeight()) { + return false; + } else { + if (!layersActionBarLayout.fragmentsStack.isEmpty()) { + for (int a = 0; a < layersActionBarLayout.fragmentsStack.size() - 1; a++) { + layersActionBarLayout.removeFragmentFromStack(layersActionBarLayout.fragmentsStack.get(0)); + a--; } - return true; + layersActionBarLayout.closeLastFragment(true); } + return true; } - return false; } + return false; }); - shadowTablet.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + shadowTablet.setOnClickListener(v -> { - } }); layersActionBarLayout = new ActionBarLayout(this); @@ -219,19 +210,16 @@ public class ExternalActionActivity extends Activity implements ActionBarLayout. passcodeView.onShow(); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(new PasscodeView.PasscodeViewDelegate() { - @Override - public void didAcceptedPassword() { - SharedConfig.isWaitingForPasscodeEnter = false; - if (passcodeSaveIntent != null) { - handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); - passcodeSaveIntent = null; - } - drawerLayoutContainer.setAllowOpenDrawer(true, false); - actionBarLayout.showLastFragment(); - if (AndroidUtilities.isTablet()) { - layersActionBarLayout.showLastFragment(); - } + passcodeView.setDelegate(() -> { + SharedConfig.isWaitingForPasscodeEnter = false; + if (passcodeSaveIntent != null) { + handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); + passcodeSaveIntent = null; + } + drawerLayoutContainer.setAllowOpenDrawer(true, false); + actionBarLayout.showLastFragment(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.showLastFragment(); } }); } @@ -290,23 +278,17 @@ public class ExternalActionActivity extends Activity implements ActionBarLayout. return true; } else if (activatedAccountsCount >= 2) { - AlertDialog alertDialog = AlertsCreator.createAccountSelectDialog(this, new AlertsCreator.AccountSelectDelegate() { - @Override - public void didSelectAccount(int account) { - if (account != intentAccount) { - switchToAccount(account); - } - handleIntent(intent, isNew, restore, fromPassword, account, 1); + AlertDialog alertDialog = AlertsCreator.createAccountSelectDialog(this, account -> { + if (account != intentAccount) { + switchToAccount(account); } + handleIntent(intent, isNew, restore, fromPassword, account, 1); }); alertDialog.show(); alertDialog.setCanceledOnTouchOutside(false); - alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - setResult(RESULT_CANCELED); - finish(); - } + alertDialog.setOnDismissListener(dialog -> { + setResult(RESULT_CANCELED); + finish(); }); return true; } @@ -317,7 +299,10 @@ public class ExternalActionActivity extends Activity implements ActionBarLayout. progressDialog.setCancelable(false); final int bot_id = intent.getIntExtra("bot_id", 0); - final String payload = intent.getStringExtra("payload"); + String _payload=intent.getStringExtra("nonce"); + if(TextUtils.isEmpty(_payload)) + _payload=intent.getStringExtra("payload"); + final String payload = _payload; final TLRPC.TL_account_getAuthorizationForm req = new TLRPC.TL_account_getAuthorizationForm(); req.bot_id = bot_id; req.scope = intent.getStringExtra("scope"); @@ -330,82 +315,65 @@ public class ExternalActionActivity extends Activity implements ActionBarLayout. } progressDialog.show(); - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - final TLRPC.TL_account_authorizationForm authorizationForm = (TLRPC.TL_account_authorizationForm) response; - if (authorizationForm != null) { - TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (response != null) { - TLRPC.account_Password accountPassword = (TLRPC.account_Password) response; - MessagesController.getInstance(intentAccount).putUsers(authorizationForm.users, false); - PassportActivity fragment = new PassportActivity(PassportActivity.TYPE_PASSWORD, req.bot_id, req.scope, req.public_key, payload, null, authorizationForm, accountPassword); - fragment.setNeedActivityResult(true); - if (AndroidUtilities.isTablet()) { - layersActionBarLayout.addFragmentToStack(fragment); - } else { - actionBarLayout.addFragmentToStack(fragment); - } - if (!AndroidUtilities.isTablet()) { - backgroundTablet.setVisibility(View.GONE); - } - actionBarLayout.showLastFragment(); - if (AndroidUtilities.isTablet()) { - layersActionBarLayout.showLastFragment(); - } - } - } - }); + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> { + final TLRPC.TL_account_authorizationForm authorizationForm = (TLRPC.TL_account_authorizationForm) response; + if (authorizationForm != null) { + TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + if (response1 != null) { + TLRPC.TL_account_password accountPassword = (TLRPC.TL_account_password) response1; + MessagesController.getInstance(intentAccount).putUsers(authorizationForm.users, false); + PassportActivity fragment = new PassportActivity(PassportActivity.TYPE_PASSWORD, req.bot_id, req.scope, req.public_key, payload, null, authorizationForm, accountPassword); + fragment.setNeedActivityResult(true); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.addFragmentToStack(fragment); + } else { + actionBarLayout.addFragmentToStack(fragment); } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - if ("APP_VERSION_OUTDATED".equals(error.text)) { - AlertDialog dialog = AlertsCreator.showUpdateAppAlert(ExternalActionActivity.this, LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); - if (dialog != null) { - dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - setResult(RESULT_FIRST_USER, new Intent().putExtra("error", error.text)); - finish(); - } - }); - } else { - setResult(RESULT_FIRST_USER, new Intent().putExtra("error", error.text)); - finish(); - } - } else if (("BOT_INVALID".equals(error.text) || - "PUBLIC_KEY_REQUIRED".equals(error.text) || - "PUBLIC_KEY_INVALID".equals(error.text) - || "SCOPE_EMPTY".equals(error.text) || - "PAYLOAD_EMPTY".equals(error.text))) { + if (!AndroidUtilities.isTablet()) { + backgroundTablet.setVisibility(View.GONE); + } + actionBarLayout.showLastFragment(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.showLastFragment(); + } + } + })); + } else { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + if ("APP_VERSION_OUTDATED".equals(error.text)) { + AlertDialog dialog = AlertsCreator.showUpdateAppAlert(ExternalActionActivity.this, LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + if (dialog != null) { + dialog.setOnDismissListener(dialog1 -> { setResult(RESULT_FIRST_USER, new Intent().putExtra("error", error.text)); finish(); - } else { - setResult(RESULT_CANCELED); - finish(); - } - } catch (Exception e) { - FileLog.e(e); + }); + } else { + setResult(RESULT_FIRST_USER, new Intent().putExtra("error", error.text)); + finish(); } + } else if (("BOT_INVALID".equals(error.text) || + "PUBLIC_KEY_REQUIRED".equals(error.text) || + "PUBLIC_KEY_INVALID".equals(error.text) + || "SCOPE_EMPTY".equals(error.text) || + "PAYLOAD_EMPTY".equals(error.text))) { + setResult(RESULT_FIRST_USER, new Intent().putExtra("error", error.text)); + finish(); + } else { + setResult(RESULT_CANCELED); + finish(); } - }); - } + } catch (Exception e) { + FileLog.e(e); + } + }); } }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 31d688f4f..9d7b50351 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -8,7 +8,6 @@ package org.telegram.ui; -import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager; import android.content.DialogInterface; @@ -49,7 +48,6 @@ import org.telegram.messenger.ContactsController; import org.telegram.messenger.DataQuery; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLoader; -import org.telegram.messenger.LocationController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; @@ -69,8 +67,6 @@ import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.support.widget.DefaultItemAnimator; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.AlertDialog; @@ -318,39 +314,33 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa shadowTablet.setVisibility(layerFragmentsStack.isEmpty() ? View.GONE : View.VISIBLE); shadowTablet.setBackgroundColor(0x7f000000); launchLayout.addView(shadowTablet); - shadowTablet.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (!actionBarLayout.fragmentsStack.isEmpty() && event.getAction() == MotionEvent.ACTION_UP) { - float x = event.getX(); - float y = event.getY(); - int location[] = new int[2]; - layersActionBarLayout.getLocationOnScreen(location); - int viewX = location[0]; - int viewY = location[1]; + shadowTablet.setOnTouchListener((v, event) -> { + if (!actionBarLayout.fragmentsStack.isEmpty() && event.getAction() == MotionEvent.ACTION_UP) { + float x = event.getX(); + float y = event.getY(); + int location[] = new int[2]; + layersActionBarLayout.getLocationOnScreen(location); + int viewX = location[0]; + int viewY = location[1]; - if (layersActionBarLayout.checkTransitionAnimation() || x > viewX && x < viewX + layersActionBarLayout.getWidth() && y > viewY && y < viewY + layersActionBarLayout.getHeight()) { - return false; - } else { - if (!layersActionBarLayout.fragmentsStack.isEmpty()) { - for (int a = 0; a < layersActionBarLayout.fragmentsStack.size() - 1; a++) { - layersActionBarLayout.removeFragmentFromStack(layersActionBarLayout.fragmentsStack.get(0)); - a--; - } - layersActionBarLayout.closeLastFragment(true); + if (layersActionBarLayout.checkTransitionAnimation() || x > viewX && x < viewX + layersActionBarLayout.getWidth() && y > viewY && y < viewY + layersActionBarLayout.getHeight()) { + return false; + } else { + if (!layersActionBarLayout.fragmentsStack.isEmpty()) { + for (int a = 0; a < layersActionBarLayout.fragmentsStack.size() - 1; a++) { + layersActionBarLayout.removeFragmentFromStack(layersActionBarLayout.fragmentsStack.get(0)); + a--; } - return true; + layersActionBarLayout.closeLastFragment(true); } + return true; } - return false; } + return false; }); - shadowTablet.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + shadowTablet.setOnClickListener(v -> { - } }); layersActionBarLayout = new ActionBarLayout(this); @@ -378,71 +368,68 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa layoutParams.width = AndroidUtilities.isTablet() ? AndroidUtilities.dp(320) : Math.min(AndroidUtilities.dp(320), Math.min(screenSize.x, screenSize.y) - AndroidUtilities.dp(56)); layoutParams.height = LayoutHelper.MATCH_PARENT; sideMenu.setLayoutParams(layoutParams); - sideMenu.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(final View view, int position) { - if (position == 0) { - drawerLayoutAdapter.setAccountsShowed(!drawerLayoutAdapter.isAccountsShowed(), true); - } else if (view instanceof DrawerUserCell) { - switchToAccount(((DrawerUserCell) view).getAccountNumber(), true); - drawerLayoutContainer.closeDrawer(false); - } else if (view instanceof DrawerAddCell) { - int freeAccount = -1; - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (!UserConfig.getInstance(a).isClientActivated()) { - freeAccount = a; - break; - } + sideMenu.setOnItemClickListener((view, position) -> { + if (position == 0) { + drawerLayoutAdapter.setAccountsShowed(!drawerLayoutAdapter.isAccountsShowed(), true); + } else if (view instanceof DrawerUserCell) { + switchToAccount(((DrawerUserCell) view).getAccountNumber(), true); + drawerLayoutContainer.closeDrawer(false); + } else if (view instanceof DrawerAddCell) { + int freeAccount = -1; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (!UserConfig.getInstance(a).isClientActivated()) { + freeAccount = a; + break; } - if (freeAccount >= 0) { - presentFragment(new LoginActivity(freeAccount)); + } + if (freeAccount >= 0) { + presentFragment(new LoginActivity(freeAccount)); + } + drawerLayoutContainer.closeDrawer(false); + } else { + int id = drawerLayoutAdapter.getId(position); + if (id == 2) { + presentFragment(new GroupCreateActivity()); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 3) { + Bundle args = new Bundle(); + args.putBoolean("onlyUsers", true); + args.putBoolean("destroyAfterSelect", true); + args.putBoolean("createSecretChat", true); + args.putBoolean("allowBots", false); + presentFragment(new ContactsActivity(args)); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 4) { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + if (!BuildVars.DEBUG_VERSION && preferences.getBoolean("channel_intro", false)) { + Bundle args = new Bundle(); + args.putInt("step", 0); + presentFragment(new ChannelCreateActivity(args)); + } else { + presentFragment(new ChannelIntroActivity()); + preferences.edit().putBoolean("channel_intro", true).commit(); } drawerLayoutContainer.closeDrawer(false); - } else { - int id = drawerLayoutAdapter.getId(position); - if (id == 2) { - presentFragment(new GroupCreateActivity()); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 3) { - Bundle args = new Bundle(); - args.putBoolean("onlyUsers", true); - args.putBoolean("destroyAfterSelect", true); - args.putBoolean("createSecretChat", true); - args.putBoolean("allowBots", false); - presentFragment(new ContactsActivity(args)); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 4) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - if (!BuildVars.DEBUG_VERSION && preferences.getBoolean("channel_intro", false)) { - Bundle args = new Bundle(); - args.putInt("step", 0); - presentFragment(new ChannelCreateActivity(args)); - } else { - presentFragment(new ChannelIntroActivity()); - preferences.edit().putBoolean("channel_intro", true).commit(); - } - drawerLayoutContainer.closeDrawer(false); - } else if (id == 6) { - presentFragment(new ContactsActivity(null)); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 7) { - presentFragment(new InviteContactsActivity()); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 8) { - presentFragment(new SettingsActivity()); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 9) { - Browser.openUrl(LaunchActivity.this, LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 10) { - presentFragment(new CallLogActivity()); - drawerLayoutContainer.closeDrawer(false); - } else if (id == 11) { - Bundle args = new Bundle(); - args.putInt("user_id", UserConfig.getInstance(currentAccount).getClientUserId()); - presentFragment(new ChatActivity(args)); - drawerLayoutContainer.closeDrawer(false); - } + } else if (id == 6) { + presentFragment(new ContactsActivity(null)); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 7) { + presentFragment(new InviteContactsActivity()); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 8) { + presentFragment(new SettingsActivity()); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 9) { + Browser.openUrl(LaunchActivity.this, LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 10) { + presentFragment(new CallLogActivity()); + drawerLayoutContainer.closeDrawer(false); + } else if (id == 11) { + Bundle args = new Bundle(); + args.putInt("user_id", UserConfig.getInstance(currentAccount).getClientUserId()); + presentFragment(new ChatActivity(args)); + drawerLayoutContainer.closeDrawer(false); } } }); @@ -585,18 +572,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (os1.contains("flyme") || os2.contains("flyme")) { AndroidUtilities.incorrectDisplaySizeFix = true; final View view = getWindow().getDecorView().getRootView(); - view.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - int height = view.getMeasuredHeight(); - if (Build.VERSION.SDK_INT >= 21) { - height -= AndroidUtilities.statusBarHeight; - } - if (height > AndroidUtilities.dp(100) && height < AndroidUtilities.displaySize.y && height + AndroidUtilities.dp(100) > AndroidUtilities.displaySize.y) { - AndroidUtilities.displaySize.y = height; - if (BuildVars.LOGS_ENABLED) { - FileLog.d("fix display size y to " + AndroidUtilities.displaySize.y); - } + view.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener = () -> { + int height = view.getMeasuredHeight(); + if (Build.VERSION.SDK_INT >= 21) { + height -= AndroidUtilities.statusBarHeight; + } + if (height > AndroidUtilities.dp(100) && height < AndroidUtilities.displaySize.y && height + AndroidUtilities.dp(100) > AndroidUtilities.displaySize.y) { + AndroidUtilities.displaySize.y = height; + if (BuildVars.LOGS_ENABLED) { + FileLog.d("fix display size y to " + AndroidUtilities.displaySize.y); } } }); @@ -822,20 +806,17 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa passcodeView.onShow(); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(new PasscodeView.PasscodeViewDelegate() { - @Override - public void didAcceptedPassword() { - SharedConfig.isWaitingForPasscodeEnter = false; - if (passcodeSaveIntent != null) { - handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true); - passcodeSaveIntent = null; - } - drawerLayoutContainer.setAllowOpenDrawer(true, false); - actionBarLayout.showLastFragment(); - if (AndroidUtilities.isTablet()) { - layersActionBarLayout.showLastFragment(); - rightActionBarLayout.showLastFragment(); - } + passcodeView.setDelegate(() -> { + SharedConfig.isWaitingForPasscodeEnter = false; + if (passcodeSaveIntent != null) { + handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true); + passcodeSaveIntent = null; + } + drawerLayoutContainer.setAllowOpenDrawer(true, false); + actionBarLayout.showLastFragment(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.showLastFragment(); + rightActionBarLayout.showLastFragment(); } }); } @@ -1140,10 +1121,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if ("telegrampassport".equals(username)) { username = null; auth = new HashMap<>(); + String scope = data.getQueryParameter("scope"); + if (!TextUtils.isEmpty(scope) && scope.startsWith("{") && scope.endsWith("}")) { + auth.put("payload", data.getQueryParameter("nonce")); + } else { + auth.put("payload", data.getQueryParameter("payload")); + } auth.put("bot_id", data.getQueryParameter("bot_id")); - auth.put("scope", data.getQueryParameter("scope")); + auth.put("scope", scope); auth.put("public_key", data.getQueryParameter("public_key")); - auth.put("payload", data.getQueryParameter("payload")); auth.put("callback_url", data.getQueryParameter("callback_url")); } else { botUser = data.getQueryParameter("start"); @@ -1216,10 +1202,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa url = url.replace("tg:passport", "tg://telegram.org").replace("tg://passport", "tg://telegram.org").replace("tg:secureid", "tg://telegram.org"); data = Uri.parse(url); auth = new HashMap<>(); + String scope = data.getQueryParameter("scope"); + if (!TextUtils.isEmpty(scope) && scope.startsWith("{") && scope.endsWith("}")) { + auth.put("payload", data.getQueryParameter("nonce")); + } else { + auth.put("payload", data.getQueryParameter("payload")); + } auth.put("bot_id", data.getQueryParameter("bot_id")); - auth.put("scope", data.getQueryParameter("scope")); + auth.put("scope", scope); auth.put("public_key", data.getQueryParameter("public_key")); - auth.put("payload", data.getQueryParameter("payload")); auth.put("callback_url", data.getQueryParameter("callback_url")); } else { unsupportedUrl = url.replace("tg://", "").replace("tg:", ""); @@ -1237,12 +1228,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa final Bundle args = new Bundle(); args.putString("phone", phone); args.putString("hash", phoneHash); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - presentFragment(new CancelAccountDeletionActivity(args)); - } - }); + AndroidUtilities.runOnUIThread(() -> presentFragment(new CancelAccountDeletionActivity(args))); } else if (username != null || group != null || sticker != null || message != null || game != null || instantView != null || auth != null || unsupportedUrl != null) { runLinkRequest(intentAccount[0], username, group, sticker, botUser, botChat, message, hasUrl, messageId, game, instantView, auth, unsupportedUrl, 0); } else { @@ -1353,23 +1339,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } else if (showLocations) { if (!actionBarLayout.fragmentsStack.isEmpty()) { BaseFragment fragment = actionBarLayout.fragmentsStack.get(0); - fragment.showDialog(new SharingLocationsAlert(this, new SharingLocationsAlert.SharingLocationsAlertDelegate() { - @Override - public void didSelectLocation(LocationController.SharingLocationInfo info) { - intentAccount[0] = info.messageObject.currentAccount; - switchToAccount(intentAccount[0], true); + fragment.showDialog(new SharingLocationsAlert(this, info -> { + intentAccount[0] = info.messageObject.currentAccount; + switchToAccount(intentAccount[0], true); - LocationActivity locationActivity = new LocationActivity(2); - locationActivity.setMessageObject(info.messageObject); - final long dialog_id = info.messageObject.getDialogId(); - locationActivity.setDelegate(new LocationActivity.LocationActivityDelegate() { - @Override - public void didSelectLocation(TLRPC.MessageMedia location, int live) { - SendMessagesHelper.getInstance(intentAccount[0]).sendMessage(location, dialog_id, null, null, null); - } - }); - presentFragment(locationActivity); - } + LocationActivity locationActivity = new LocationActivity(2); + locationActivity.setMessageObject(info.messageObject); + final long dialog_id = info.messageObject.getDialogId(); + locationActivity.setDelegate((location, live) -> SendMessagesHelper.getInstance(intentAccount[0]).sendMessage(location, dialog_id, null, null, null)); + presentFragment(locationActivity); })); } pushOpened = false; @@ -1488,14 +1466,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa private void runLinkRequest(final int intentAccount, final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final boolean hasUrl, final Integer messageId, final String game, final String[] instantView, final HashMap auth, final String unsupportedUrl, final int state) { if (state == 0 && UserConfig.getActivatedAccountsCount() >= 2 && auth != null) { - AlertsCreator.createAccountSelectDialog(this, new AlertsCreator.AccountSelectDelegate() { - @Override - public void didSelectAccount(int account) { - if (account != intentAccount) { - switchToAccount(account, true); - } - runLinkRequest(account, username, group, sticker, botUser, botChat, message, hasUrl, messageId, game, instantView, auth, unsupportedUrl, 1); + AlertsCreator.createAccountSelectDialog(this, account -> { + if (account != intentAccount) { + switchToAccount(account, true); } + runLinkRequest(account, username, group, sticker, botUser, botChat, message, hasUrl, messageId, game, instantView, auth, unsupportedUrl, 1); }).show(); return; } @@ -1508,274 +1483,241 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (username != null) { TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); req.username = username; - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!LaunchActivity.this.isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - final TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; - if (error == null && actionBarLayout != null && (game == null || game != null && !res.users.isEmpty())) { - MessagesController.getInstance(intentAccount).putUsers(res.users, false); - MessagesController.getInstance(intentAccount).putChats(res.chats, false); - MessagesStorage.getInstance(intentAccount).putUsersAndChats(res.users, res.chats, false, true); - if (game != null) { - Bundle args = new Bundle(); - args.putBoolean("onlySelect", true); - args.putBoolean("cantSendToChannels", true); - args.putInt("dialogsType", 1); - args.putString("selectAlertString", LocaleController.getString("SendGameTo", R.string.SendGameTo)); - args.putString("selectAlertStringGroup", LocaleController.getString("SendGameToGroup", R.string.SendGameToGroup)); - DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - long did = dids.get(0); - TLRPC.TL_inputMediaGame inputMediaGame = new TLRPC.TL_inputMediaGame(); - inputMediaGame.id = new TLRPC.TL_inputGameShortName(); - inputMediaGame.id.short_name = game; - inputMediaGame.id.bot_id = MessagesController.getInstance(intentAccount).getInputUser(res.users.get(0)); - SendMessagesHelper.getInstance(intentAccount).sendGame(MessagesController.getInstance(intentAccount).getInputPeer((int) did), inputMediaGame, 0, 0); + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (!LaunchActivity.this.isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + final TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + if (error == null && actionBarLayout != null && (game == null || game != null && !res.users.isEmpty())) { + MessagesController.getInstance(intentAccount).putUsers(res.users, false); + MessagesController.getInstance(intentAccount).putChats(res.chats, false); + MessagesStorage.getInstance(intentAccount).putUsersAndChats(res.users, res.chats, false, true); + if (game != null) { + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putBoolean("cantSendToChannels", true); + args.putInt("dialogsType", 1); + args.putString("selectAlertString", LocaleController.getString("SendGameTo", R.string.SendGameTo)); + args.putString("selectAlertStringGroup", LocaleController.getString("SendGameToGroup", R.string.SendGameToGroup)); + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate((fragment1, dids, message1, param) -> { + long did = dids.get(0); + TLRPC.TL_inputMediaGame inputMediaGame = new TLRPC.TL_inputMediaGame(); + inputMediaGame.id = new TLRPC.TL_inputGameShortName(); + inputMediaGame.id.short_name = game; + inputMediaGame.id.bot_id = MessagesController.getInstance(intentAccount).getInputUser(res.users.get(0)); + SendMessagesHelper.getInstance(intentAccount).sendGame(MessagesController.getInstance(intentAccount).getInputPeer((int) did), inputMediaGame, 0, 0); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - int lower_part = (int) did; - int high_id = (int) (did >> 32); - if (lower_part != 0) { - if (high_id == 1) { - args.putInt("chat_id", lower_part); - } else { - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - args.putInt("chat_id", -lower_part); - } - } - } else { - args.putInt("enc_id", high_id); - } - if (MessagesController.getInstance(intentAccount).checkCanOpenChat(args, fragment)) { - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(new ChatActivity(args), true, false, true, false); - } - } - }); - boolean removeLast; - if (AndroidUtilities.isTablet()) { - removeLast = layersActionBarLayout.fragmentsStack.size() > 0 && layersActionBarLayout.fragmentsStack.get(layersActionBarLayout.fragmentsStack.size() - 1) instanceof DialogsActivity; - } else { - removeLast = actionBarLayout.fragmentsStack.size() > 1 && actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1) instanceof DialogsActivity; - } - actionBarLayout.presentFragment(fragment, removeLast, true, true, false); - if (SecretMediaViewer.hasInstance() && SecretMediaViewer.getInstance().isVisible()) { - SecretMediaViewer.getInstance().closePhoto(false, false); - } else if (PhotoViewer.hasInstance() && PhotoViewer.getInstance().isVisible()) { - PhotoViewer.getInstance().closePhoto(false, true); - } else if (ArticleViewer.hasInstance() && ArticleViewer.getInstance().isVisible()) { - ArticleViewer.getInstance().close(false, true); - } - drawerLayoutContainer.setAllowOpenDrawer(false, false); - if (AndroidUtilities.isTablet()) { - actionBarLayout.showLastFragment(); - rightActionBarLayout.showLastFragment(); - } else { - drawerLayoutContainer.setAllowOpenDrawer(true, false); - } - } else if (botChat != null) { - final TLRPC.User user = !res.users.isEmpty() ? res.users.get(0) : null; - if (user == null || user.bot && user.bot_nochats) { - try { - Toast.makeText(LaunchActivity.this, LocaleController.getString("BotCantJoinGroups", R.string.BotCantJoinGroups), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } - return; - } - Bundle args = new Bundle(); - args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 2); - args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupTitle", R.string.AddToTheGroupTitle, UserObject.getUserName(user), "%1$s")); - DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - long did = dids.get(0); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - args.putInt("chat_id", -(int) did); - if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance(intentAccount).addUserToChat(-(int) did, user, null, 0, botChat, null); - actionBarLayout.presentFragment(new ChatActivity(args), true, false, true, false); - } - } - }); - presentFragment(fragment); + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + int lower_part = (int) did; + int high_id = (int) (did >> 32); + if (lower_part != 0) { + if (high_id == 1) { + args1.putInt("chat_id", lower_part); } else { - long dialog_id; - boolean isBot = false; - Bundle args = new Bundle(); - if (!res.chats.isEmpty()) { - args.putInt("chat_id", res.chats.get(0).id); - dialog_id = -res.chats.get(0).id; - } else { - args.putInt("user_id", res.users.get(0).id); - dialog_id = res.users.get(0).id; - } - if (botUser != null && res.users.size() > 0 && res.users.get(0).bot) { - args.putString("botUser", botUser); - isBot = true; - } - if (messageId != null) { - args.putInt("message_id", messageId); - } - BaseFragment lastFragment = !mainFragmentsStack.isEmpty() ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; - if (lastFragment == null || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, lastFragment)) { - if (isBot && lastFragment != null && lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == dialog_id) { - ((ChatActivity) lastFragment).setBotUser(botUser); - } else { - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true, false); - } + if (lower_part > 0) { + args1.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args1.putInt("chat_id", -lower_part); } } } else { - try { - Toast.makeText(LaunchActivity.this, LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } + args1.putInt("enc_id", high_id); + } + if (MessagesController.getInstance(intentAccount).checkCanOpenChat(args1, fragment1)) { + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(new ChatActivity(args1), true, false, true, false); + } + }); + boolean removeLast; + if (AndroidUtilities.isTablet()) { + removeLast = layersActionBarLayout.fragmentsStack.size() > 0 && layersActionBarLayout.fragmentsStack.get(layersActionBarLayout.fragmentsStack.size() - 1) instanceof DialogsActivity; + } else { + removeLast = actionBarLayout.fragmentsStack.size() > 1 && actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1) instanceof DialogsActivity; + } + actionBarLayout.presentFragment(fragment, removeLast, true, true, false); + if (SecretMediaViewer.hasInstance() && SecretMediaViewer.getInstance().isVisible()) { + SecretMediaViewer.getInstance().closePhoto(false, false); + } else if (PhotoViewer.hasInstance() && PhotoViewer.getInstance().isVisible()) { + PhotoViewer.getInstance().closePhoto(false, true); + } else if (ArticleViewer.hasInstance() && ArticleViewer.getInstance().isVisible()) { + ArticleViewer.getInstance().close(false, true); + } + drawerLayoutContainer.setAllowOpenDrawer(false, false); + if (AndroidUtilities.isTablet()) { + actionBarLayout.showLastFragment(); + rightActionBarLayout.showLastFragment(); + } else { + drawerLayoutContainer.setAllowOpenDrawer(true, false); + } + } else if (botChat != null) { + final TLRPC.User user = !res.users.isEmpty() ? res.users.get(0) : null; + if (user == null || user.bot && user.bot_nochats) { + try { + Toast.makeText(LaunchActivity.this, LocaleController.getString("BotCantJoinGroups", R.string.BotCantJoinGroups), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); + } + return; + } + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", 2); + args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupTitle", R.string.AddToTheGroupTitle, UserObject.getUserName(user), "%1$s")); + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate((fragment12, dids, message1, param) -> { + long did = dids.get(0); + Bundle args12 = new Bundle(); + args12.putBoolean("scrollToTopOnResume", true); + args12.putInt("chat_id", -(int) did); + if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args12, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance(intentAccount).addUserToChat(-(int) did, user, null, 0, botChat, null); + actionBarLayout.presentFragment(new ChatActivity(args12), true, false, true, false); + } + }); + presentFragment(fragment); + } else { + long dialog_id; + boolean isBot = false; + Bundle args = new Bundle(); + if (!res.chats.isEmpty()) { + args.putInt("chat_id", res.chats.get(0).id); + dialog_id = -res.chats.get(0).id; + } else { + args.putInt("user_id", res.users.get(0).id); + dialog_id = res.users.get(0).id; + } + if (botUser != null && res.users.size() > 0 && res.users.get(0).bot) { + args.putString("botUser", botUser); + isBot = true; + } + if (messageId != null) { + args.putInt("message_id", messageId); + } + BaseFragment lastFragment = !mainFragmentsStack.isEmpty() ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; + if (lastFragment == null || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, lastFragment)) { + if (isBot && lastFragment != null && lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == dialog_id) { + ((ChatActivity) lastFragment).setBotUser(botUser); + } else { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true, false); } } } - }); + } else { + try { + Toast.makeText(LaunchActivity.this, LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); + } + } } - }); + })); } else if (group != null) { if (state == 0) { final TLRPC.TL_messages_checkChatInvite req = new TLRPC.TL_messages_checkChatInvite(); req.hash = group; - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!LaunchActivity.this.isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (error == null && actionBarLayout != null) { - TLRPC.ChatInvite invite = (TLRPC.ChatInvite) response; - if (invite.chat != null && !ChatObject.isLeftFromChat(invite.chat)) { - MessagesController.getInstance(intentAccount).putChat(invite.chat, false); - ArrayList chats = new ArrayList<>(); - chats.add(invite.chat); - MessagesStorage.getInstance(intentAccount).putUsersAndChats(null, chats, false, true); - Bundle args = new Bundle(); - args.putInt("chat_id", invite.chat.id); - if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true, false); - } - } else { - if ((invite.chat == null && (!invite.channel || invite.megagroup) || invite.chat != null && (!ChatObject.isChannel(invite.chat) || invite.chat.megagroup)) && !mainFragmentsStack.isEmpty()) { - BaseFragment fragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); - fragment.showDialog(new JoinGroupAlert(LaunchActivity.this, invite, group, fragment)); - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.formatString("ChannelJoinTo", R.string.ChannelJoinTo, invite.chat != null ? invite.chat.title : invite.title)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - runLinkRequest(intentAccount, username, group, sticker, botUser, botChat, message, hasUrl, messageId, game, instantView, auth, unsupportedUrl, 1); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showAlertDialog(builder); - } - } - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (error.text.startsWith("FLOOD_WAIT")) { - builder.setMessage(LocaleController.getString("FloodWait", R.string.FloodWait)); - } else { - builder.setMessage(LocaleController.getString("JoinToGroupErrorNotExist", R.string.JoinToGroupErrorNotExist)); - } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showAlertDialog(builder); - } + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (!LaunchActivity.this.isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + if (error == null && actionBarLayout != null) { + TLRPC.ChatInvite invite = (TLRPC.ChatInvite) response; + if (invite.chat != null && !ChatObject.isLeftFromChat(invite.chat)) { + MessagesController.getInstance(intentAccount).putChat(invite.chat, false); + ArrayList chats = new ArrayList<>(); + chats.add(invite.chat); + MessagesStorage.getInstance(intentAccount).putUsersAndChats(null, chats, false, true); + Bundle args = new Bundle(); + args.putInt("chat_id", invite.chat.id); + if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true, false); + } + } else { + if ((invite.chat == null && (!invite.channel || invite.megagroup) || invite.chat != null && (!ChatObject.isChannel(invite.chat) || invite.chat.megagroup)) && !mainFragmentsStack.isEmpty()) { + BaseFragment fragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + fragment.showDialog(new JoinGroupAlert(LaunchActivity.this, invite, group, fragment)); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.formatString("ChannelJoinTo", R.string.ChannelJoinTo, invite.chat != null ? invite.chat.title : invite.title)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> runLinkRequest(intentAccount, username, group, sticker, botUser, botChat, message, hasUrl, messageId, game, instantView, auth, unsupportedUrl, 1)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showAlertDialog(builder); } } - }); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (error.text.startsWith("FLOOD_WAIT")) { + builder.setMessage(LocaleController.getString("FloodWait", R.string.FloodWait)); + } else { + builder.setMessage(LocaleController.getString("JoinToGroupErrorNotExist", R.string.JoinToGroupErrorNotExist)); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showAlertDialog(builder); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } else if (state == 1) { TLRPC.TL_messages_importChatInvite req = new TLRPC.TL_messages_importChatInvite(); req.hash = group; - ConnectionsManager.getInstance(intentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (error == null) { - TLRPC.Updates updates = (TLRPC.Updates) response; - MessagesController.getInstance(intentAccount).processUpdates(updates, false); - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!LaunchActivity.this.isFinishing()) { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (error == null) { - if (actionBarLayout != null) { - TLRPC.Updates updates = (TLRPC.Updates) response; - if (!updates.chats.isEmpty()) { - TLRPC.Chat chat = updates.chats.get(0); - chat.left = false; - chat.kicked = false; - MessagesController.getInstance(intentAccount).putUsers(updates.users, false); - MessagesController.getInstance(intentAccount).putChats(updates.chats, false); - Bundle args = new Bundle(); - args.putInt("chat_id", chat.id); - if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true, false); - } - } + ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + MessagesController.getInstance(intentAccount).processUpdates(updates, false); + } + AndroidUtilities.runOnUIThread(() -> { + if (!LaunchActivity.this.isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + if (error == null) { + if (actionBarLayout != null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + if (!updates.chats.isEmpty()) { + TLRPC.Chat chat = updates.chats.get(0); + chat.left = false; + chat.kicked = false; + MessagesController.getInstance(intentAccount).putUsers(updates.users, false); + MessagesController.getInstance(intentAccount).putChats(updates.chats, false); + Bundle args = new Bundle(); + args.putInt("chat_id", chat.id); + if (mainFragmentsStack.isEmpty() || MessagesController.getInstance(intentAccount).checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true, false); } - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (error.text.startsWith("FLOOD_WAIT")) { - builder.setMessage(LocaleController.getString("FloodWait", R.string.FloodWait)); - } else if (error.text.equals("USERS_TOO_MUCH")) { - builder.setMessage(LocaleController.getString("JoinToGroupErrorFull", R.string.JoinToGroupErrorFull)); - } else { - builder.setMessage(LocaleController.getString("JoinToGroupErrorNotExist", R.string.JoinToGroupErrorNotExist)); - } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showAlertDialog(builder); } } + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (error.text.startsWith("FLOOD_WAIT")) { + builder.setMessage(LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.text.equals("USERS_TOO_MUCH")) { + builder.setMessage(LocaleController.getString("JoinToGroupErrorFull", R.string.JoinToGroupErrorFull)); + } else { + builder.setMessage(LocaleController.getString("JoinToGroupErrorNotExist", R.string.JoinToGroupErrorNotExist)); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showAlertDialog(builder); } - }); - } + } + }); }, ConnectionsManager.RequestFlagFailOnServerErrors); } } else if (sticker != null) { @@ -1790,33 +1732,30 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa Bundle args = new Bundle(); args.putBoolean("onlySelect", true); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence m, boolean param) { - long did = dids.get(0); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - args.putBoolean("hasUrl", hasUrl); - int lower_part = (int) did; - int high_id = (int) (did >> 32); - if (lower_part != 0) { - if (high_id == 1) { - args.putInt("chat_id", lower_part); - } else { - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - args.putInt("chat_id", -lower_part); - } - } + fragment.setDelegate((fragment13, dids, m, param) -> { + long did = dids.get(0); + Bundle args13 = new Bundle(); + args13.putBoolean("scrollToTopOnResume", true); + args13.putBoolean("hasUrl", hasUrl); + int lower_part = (int) did; + int high_id = (int) (did >> 32); + if (lower_part != 0) { + if (high_id == 1) { + args13.putInt("chat_id", lower_part); } else { - args.putInt("enc_id", high_id); - } - if (MessagesController.getInstance(intentAccount).checkCanOpenChat(args, fragment)) { - NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); - DataQuery.getInstance(intentAccount).saveDraft(did, message, null, null, false); - actionBarLayout.presentFragment(new ChatActivity(args), true, false, true, false); + if (lower_part > 0) { + args13.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args13.putInt("chat_id", -lower_part); + } } + } else { + args13.putInt("enc_id", high_id); + } + if (MessagesController.getInstance(intentAccount).checkCanOpenChat(args13, fragment13)) { + NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); + DataQuery.getInstance(intentAccount).saveDraft(did, message, null, null, false); + actionBarLayout.presentFragment(new ChatActivity(args13), true, false, true, false); } }); presentFragment(fragment, false, true); @@ -1833,87 +1772,61 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa req.bot_id = bot_id; req.scope = auth.get("scope"); req.public_key = auth.get("public_key"); - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - final TLRPC.TL_account_authorizationForm authorizationForm = (TLRPC.TL_account_authorizationForm) response; - if (authorizationForm != null) { - TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); - requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (response != null) { - TLRPC.account_Password accountPassword = (TLRPC.account_Password) response; - MessagesController.getInstance(intentAccount).putUsers(authorizationForm.users, false); - presentFragment(new PassportActivity(PassportActivity.TYPE_PASSWORD, req.bot_id, req.scope, req.public_key, payload, callbackUrl, authorizationForm, accountPassword)); - } - } - }); + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> { + final TLRPC.TL_account_authorizationForm authorizationForm = (TLRPC.TL_account_authorizationForm) response; + if (authorizationForm != null) { + TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); + requestId[0] = ConnectionsManager.getInstance(intentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + if (response1 != null) { + TLRPC.TL_account_password accountPassword = (TLRPC.TL_account_password) response1; + MessagesController.getInstance(intentAccount).putUsers(authorizationForm.users, false); + presentFragment(new PassportActivity(PassportActivity.TYPE_PASSWORD, req.bot_id, req.scope, req.public_key, payload, callbackUrl, authorizationForm, accountPassword)); + } + })); + } else { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + if ("APP_VERSION_OUTDATED".equals(error.text)) { + AlertsCreator.showUpdateAppAlert(LaunchActivity.this, LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + } else { + showAlertDialog(AlertsCreator.createSimpleAlert(LaunchActivity.this, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text)); } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - if ("APP_VERSION_OUTDATED".equals(error.text)) { - AlertsCreator.showUpdateAppAlert(LaunchActivity.this, LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); - } else { - showAlertDialog(AlertsCreator.createSimpleAlert(LaunchActivity.this, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text)); - } - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } + } catch (Exception e) { + FileLog.e(e); + } + }); } }); } else if (unsupportedUrl != null) { TLRPC.TL_help_getDeepLinkInfo req = new TLRPC.TL_help_getDeepLinkInfo(); req.path = unsupportedUrl; - requestId[0] = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - - if (response instanceof TLRPC.TL_help_deepLinkInfo) { - TLRPC.TL_help_deepLinkInfo res = (TLRPC.TL_help_deepLinkInfo) response; - AlertsCreator.showUpdateAppAlert(LaunchActivity.this, res.message, res.update_app); - } - } - }); - + requestId[0] = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } - }); + + if (response instanceof TLRPC.TL_help_deepLinkInfo) { + TLRPC.TL_help_deepLinkInfo res = (TLRPC.TL_help_deepLinkInfo) response; + AlertsCreator.showUpdateAppAlert(LaunchActivity.this, res.message, res.update_app); + } + })); } if (requestId[0] != 0) { - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ConnectionsManager.getInstance(intentAccount).cancelRequest(requestId[0], true); - try { - dialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + ConnectionsManager.getInstance(intentAccount).cancelRequest(requestId[0], true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } }); try { @@ -1941,37 +1854,31 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa req.source = ""; } final int accountNum = currentAccount; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - UserConfig.getInstance(0).lastUpdateCheckTime = System.currentTimeMillis(); - UserConfig.getInstance(0).saveConfig(false); - if (response instanceof TLRPC.TL_help_appUpdate) { - final TLRPC.TL_help_appUpdate res = (TLRPC.TL_help_appUpdate) response; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (BuildVars.DEBUG_PRIVATE_VERSION) { - res.popup = Utilities.random.nextBoolean(); - } - if (!res.popup) { - (new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show(); - } else { - UserConfig.getInstance(0).pendingAppUpdate = res; - UserConfig.getInstance(0).pendingAppUpdateBuildVersion = BuildVars.BUILD_VERSION; - try { - PackageInfo packageInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - UserConfig.getInstance(0).pendingAppUpdateInstallTime = Math.max(packageInfo.lastUpdateTime, packageInfo.firstInstallTime); - } catch (Exception e) { - FileLog.e(e); - UserConfig.getInstance(0).pendingAppUpdateInstallTime = 0; - } - UserConfig.getInstance(0).saveConfig(false); - showUpdateActivity(accountNum, res); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + UserConfig.getInstance(0).lastUpdateCheckTime = System.currentTimeMillis(); + UserConfig.getInstance(0).saveConfig(false); + if (response instanceof TLRPC.TL_help_appUpdate) { + final TLRPC.TL_help_appUpdate res = (TLRPC.TL_help_appUpdate) response; + AndroidUtilities.runOnUIThread(() -> { + if (BuildVars.DEBUG_PRIVATE_VERSION) { + res.popup = Utilities.random.nextBoolean(); + } + if (!res.popup) { + (new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show(); + } else { + UserConfig.getInstance(0).pendingAppUpdate = res; + UserConfig.getInstance(0).pendingAppUpdateBuildVersion = BuildVars.BUILD_VERSION; + try { + PackageInfo packageInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + UserConfig.getInstance(0).pendingAppUpdateInstallTime = Math.max(packageInfo.lastUpdateTime, packageInfo.firstInstallTime); + } catch (Exception e) { + FileLog.e(e); + UserConfig.getInstance(0).pendingAppUpdateInstallTime = 0; } - }); - } + UserConfig.getInstance(0).saveConfig(false); + showUpdateActivity(accountNum, res); + } + }); } }); } @@ -2060,12 +1967,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (contactsToSend != null && contactsToSend.size() == 1) { if (contactsToSend.size() == 1) { PhonebookShareActivity contactFragment = new PhonebookShareActivity(null, contactsToSendUri, null, null); - contactFragment.setDelegate(new PhonebookSelectActivity.PhonebookSelectActivityDelegate() { - @Override - public void didSelectContact(TLRPC.User user) { - actionBarLayout.presentFragment(fragment, true, false, true, false); - SendMessagesHelper.getInstance(account).sendMessage(user, did, null, null, null); - } + contactFragment.setDelegate(user -> { + actionBarLayout.presentFragment(fragment, true, false, true, false); + SendMessagesHelper.getInstance(account).sendMessage(user, did, null, null, null); }); actionBarLayout.presentFragment(contactFragment, dialogsFragment != null, dialogsFragment == null, true, false); } @@ -2218,17 +2122,13 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } else if (requestCode == 19 || requestCode == 20 || requestCode == 22) { builder.setMessage(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); } - builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { - @TargetApi(Build.VERSION_CODES.GINGERBREAD) - @Override - public void onClick(DialogInterface dialog, int which) { - try { - Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); - startActivity(intent); - } catch (Exception e) { - FileLog.e(e); - } + builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + startActivity(intent); + } catch (Exception e) { + FileLog.e(e); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); @@ -2261,12 +2161,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa super.onPause(); SharedConfig.lastAppPauseTime = System.currentTimeMillis(); ApplicationLoader.mainInterfacePaused = true; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ApplicationLoader.mainInterfacePausedStageQueue = true; - ApplicationLoader.mainInterfacePausedStageQueueTime = 0; - } + Utilities.stageQueue.postRunnable(() -> { + ApplicationLoader.mainInterfacePausedStageQueue = true; + ApplicationLoader.mainInterfacePausedStageQueueTime = 0; }); onPasscodePause(); actionBarLayout.onPause(); @@ -2355,12 +2252,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa showLanguageAlert(false); ApplicationLoader.mainInterfacePaused = false; NotificationsController.lastNoDataNotificationTime = 0; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ApplicationLoader.mainInterfacePausedStageQueue = false; - ApplicationLoader.mainInterfacePausedStageQueueTime = System.currentTimeMillis(); - } + Utilities.stageQueue.postRunnable(() -> { + ApplicationLoader.mainInterfacePausedStageQueue = false; + ApplicationLoader.mainInterfacePausedStageQueueTime = System.currentTimeMillis(); }); checkFreeDiscSpace(); MediaController.checkGallery(); @@ -2462,12 +2356,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); if (reason != 2 && reason != 3) { - builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (!mainFragmentsStack.isEmpty()) { - MessagesController.getInstance(account).openByUserName("spambot", mainFragmentsStack.get(mainFragmentsStack.size() - 1), 1); - } + builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), (dialogInterface, i) -> { + if (!mainFragmentsStack.isEmpty()) { + MessagesController.getInstance(account).openByUserName("spambot", mainFragmentsStack.get(mainFragmentsStack.size() - 1), 1); } }); } @@ -2482,12 +2373,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa String type = (String) args[2]; if (type.startsWith("AUTH_KEY_DROP_")) { builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setNegativeButton(LocaleController.getString("LogOut", R.string.LogOut), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - MessagesController.getInstance(currentAccount).performLogout(2); - } - }); + builder.setNegativeButton(LocaleController.getString("LogOut", R.string.LogOut), (dialog, which) -> MessagesController.getInstance(currentAccount).performLogout(2)); } else { builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); } @@ -2505,28 +2391,22 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setNegativeButton(LocaleController.getString("ShareYouLocationUnableManually", R.string.ShareYouLocationUnableManually), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (mainFragmentsStack.isEmpty()) { - return; - } - BaseFragment lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); - if (!AndroidUtilities.isGoogleMapsInstalled(lastFragment)) { - return; - } - LocationActivity fragment = new LocationActivity(0); - fragment.setDelegate(new LocationActivity.LocationActivityDelegate() { - @Override - public void didSelectLocation(TLRPC.MessageMedia location, int live) { - for (HashMap.Entry entry : waitingForLocation.entrySet()) { - MessageObject messageObject = entry.getValue(); - SendMessagesHelper.getInstance(account).sendMessage(location, messageObject.getDialogId(), messageObject, null, null); - } - } - }); - presentFragment(fragment); + builder.setNegativeButton(LocaleController.getString("ShareYouLocationUnableManually", R.string.ShareYouLocationUnableManually), (dialogInterface, i) -> { + if (mainFragmentsStack.isEmpty()) { + return; } + BaseFragment lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + if (!AndroidUtilities.isGoogleMapsInstalled(lastFragment)) { + return; + } + LocationActivity fragment = new LocationActivity(0); + fragment.setDelegate((location, live) -> { + for (HashMap.Entry entry : waitingForLocation.entrySet()) { + MessageObject messageObject = entry.getValue(); + SendMessagesHelper.getInstance(account).sendMessage(location, messageObject.getDialogId(), messageObject, null, null); + } + }); + presentFragment(fragment); }); builder.setMessage(LocaleController.getString("ShareYouLocationUnable", R.string.ShareYouLocationUnable)); if (!mainFragmentsStack.isEmpty()) { @@ -2576,24 +2456,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); builder.setTitle(LocaleController.getString("UpdateContactsTitle", R.string.UpdateContactsTitle)); builder.setMessage(LocaleController.getString("UpdateContactsMessage", R.string.UpdateContactsMessage)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, false); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, true); - } - }); - builder.setOnBackButtonListener(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, true); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, false)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, true)); + builder.setOnBackButtonListener((dialogInterface, i) -> ContactsController.getInstance(account).syncPhoneBookByAlert(contactHashMap, first, schedule, true)); AlertDialog dialog = builder.create(); fragment.showDialog(dialog); dialog.setCanceledOnTouchOutside(false); @@ -2649,43 +2514,37 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (Build.VERSION.SDK_INT >= 26) { return; } - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - if (!UserConfig.getInstance(currentAccount).isClientActivated()) { - return; - } - try { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - if (Math.abs(preferences.getLong("last_space_check", 0) - System.currentTimeMillis()) >= 3 * 24 * 3600 * 1000) { - File path = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); - if (path == null) { - return; - } - long freeSpace; - StatFs statFs = new StatFs(path.getAbsolutePath()); - if (android.os.Build.VERSION.SDK_INT < 18) { - freeSpace = Math.abs(statFs.getAvailableBlocks() * statFs.getBlockSize()); - } else { - freeSpace = statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong(); - } - preferences.edit().putLong("last_space_check", System.currentTimeMillis()).commit(); - if (freeSpace < 1024 * 1024 * 100) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - AlertsCreator.createFreeSpaceDialog(LaunchActivity.this).show(); - } catch (Throwable ignore) { - - } - } - }); - } + Utilities.globalQueue.postRunnable(() -> { + if (!UserConfig.getInstance(currentAccount).isClientActivated()) { + return; + } + try { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + if (Math.abs(preferences.getLong("last_space_check", 0) - System.currentTimeMillis()) >= 3 * 24 * 3600 * 1000) { + File path = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); + if (path == null) { + return; } - } catch (Throwable ignore) { + long freeSpace; + StatFs statFs = new StatFs(path.getAbsolutePath()); + if (Build.VERSION.SDK_INT < 18) { + freeSpace = Math.abs(statFs.getAvailableBlocks() * statFs.getBlockSize()); + } else { + freeSpace = statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong(); + } + preferences.edit().putLong("last_space_check", System.currentTimeMillis()).commit(); + if (freeSpace < 1024 * 1024 * 100) { + AndroidUtilities.runOnUIThread(() -> { + try { + AlertsCreator.createFreeSpaceDialog(LaunchActivity.this).show(); + } catch (Throwable ignore) { + } + }); + } } + } catch (Throwable ignore) { + } }, 2000); } @@ -2714,39 +2573,30 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa cells[a].setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 2)); cells[a].setLanguageSelected(a == 0); linearLayout.addView(cells[a], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - cells[a].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Integer tag = (Integer) v.getTag(); - selectedLanguage[0] = ((LanguageCell) v).getCurrentLocale(); - for (int a = 0; a < cells.length; a++) { - cells[a].setLanguageSelected(a == tag); - } + cells[a].setOnClickListener(v -> { + Integer tag = (Integer) v.getTag(); + selectedLanguage[0] = ((LanguageCell) v).getCurrentLocale(); + for (int a1 = 0; a1 < cells.length; a1++) { + cells[a1].setLanguageSelected(a1 == tag); } }); } LanguageCell cell = new LanguageCell(LaunchActivity.this, true); cell.setValue(getStringForLanguageAlert(systemLocaleStrings, "ChooseYourLanguageOther", R.string.ChooseYourLanguageOther), getStringForLanguageAlert(englishLocaleStrings, "ChooseYourLanguageOther", R.string.ChooseYourLanguageOther)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - localeDialog = null; - drawerLayoutContainer.closeDrawer(true); - presentFragment(new LanguageSelectActivity()); - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; - } + cell.setOnClickListener(v -> { + localeDialog = null; + drawerLayoutContainer.closeDrawer(true); + presentFragment(new LanguageSelectActivity()); + if (visibleDialog != null) { + visibleDialog.dismiss(); + visibleDialog = null; } }); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); builder.setView(linearLayout); - builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - LocaleController.getInstance().applyLanguage(selectedLanguage[0], true, false, currentAccount); - rebuildAllFragments(true); - } + builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + LocaleController.getInstance().applyLanguage(selectedLanguage[0], true, false, currentAccount); + rebuildAllFragments(true); }); localeDialog = showAlertDialog(builder); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -2812,27 +2662,21 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa req.keys.add("ChooseYourLanguage"); req.keys.add("ChooseYourLanguageOther"); req.keys.add("ChangeLanguageLater"); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - final HashMap keys = new HashMap<>(); - if (response != null) { - TLRPC.Vector vector = (TLRPC.Vector) response; - for (int a = 0; a < vector.objects.size(); a++) { - final TLRPC.LangPackString string = (TLRPC.LangPackString) vector.objects.get(a); - keys.put(string.key, string.value); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + final HashMap keys = new HashMap<>(); + if (response != null) { + TLRPC.Vector vector = (TLRPC.Vector) response; + for (int a = 0; a < vector.objects.size(); a++) { + final TLRPC.LangPackString string = (TLRPC.LangPackString) vector.objects.get(a); + keys.put(string.key, string.value); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - systemLocaleStrings = keys; - if (englishLocaleStrings != null && systemLocaleStrings != null) { - showLanguageAlertInternal(infos[1], infos[0], systemLang); - } - } - }); } + AndroidUtilities.runOnUIThread(() -> { + systemLocaleStrings = keys; + if (englishLocaleStrings != null && systemLocaleStrings != null) { + showLanguageAlertInternal(infos[1], infos[0], systemLang); + } + }); }, ConnectionsManager.RequestFlagWithoutLogin); req = new TLRPC.TL_langpack_getStrings(); @@ -2841,27 +2685,21 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa req.keys.add("ChooseYourLanguage"); req.keys.add("ChooseYourLanguageOther"); req.keys.add("ChangeLanguageLater"); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - final HashMap keys = new HashMap<>(); - if (response != null) { - TLRPC.Vector vector = (TLRPC.Vector) response; - for (int a = 0; a < vector.objects.size(); a++) { - final TLRPC.LangPackString string = (TLRPC.LangPackString) vector.objects.get(a); - keys.put(string.key, string.value); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + final HashMap keys = new HashMap<>(); + if (response != null) { + TLRPC.Vector vector = (TLRPC.Vector) response; + for (int a = 0; a < vector.objects.size(); a++) { + final TLRPC.LangPackString string = (TLRPC.LangPackString) vector.objects.get(a); + keys.put(string.key, string.value); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - englishLocaleStrings = keys; - if (englishLocaleStrings != null && systemLocaleStrings != null) { - showLanguageAlertInternal(infos[1], infos[0], systemLang); - } - } - }); } + AndroidUtilities.runOnUIThread(() -> { + englishLocaleStrings = keys; + if (englishLocaleStrings != null && systemLocaleStrings != null) { + showLanguageAlertInternal(infos[1], infos[0], systemLang); + } + }); }, ConnectionsManager.RequestFlagWithoutLogin); } catch (Exception e) { FileLog.e(e); @@ -2935,24 +2773,21 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa title = LocaleController.getString("Connecting", R.string.Connecting); } if (currentConnectionState == ConnectionsManager.ConnectionStateConnecting || currentConnectionState == ConnectionsManager.ConnectionStateConnectingToProxy) { - action = new Runnable() { - @Override - public void run() { - BaseFragment lastFragment = null; - if (AndroidUtilities.isTablet()) { - if (!layerFragmentsStack.isEmpty()) { - lastFragment = layerFragmentsStack.get(layerFragmentsStack.size() - 1); - } - } else { - if (!mainFragmentsStack.isEmpty()) { - lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); - } + action = () -> { + BaseFragment lastFragment = null; + if (AndroidUtilities.isTablet()) { + if (!layerFragmentsStack.isEmpty()) { + lastFragment = layerFragmentsStack.get(layerFragmentsStack.size() - 1); } - if (lastFragment instanceof ProxyListActivity || lastFragment instanceof ProxySettingsActivity) { - return; + } else { + if (!mainFragmentsStack.isEmpty()) { + lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); } - presentFragment(new ProxyListActivity()); } + if (lastFragment instanceof ProxyListActivity || lastFragment instanceof ProxySettingsActivity) { + return; + } + presentFragment(new ProxyListActivity()); }; } actionBarLayout.setTitleOverlayText(title, null, action); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 637c3a117..b07886b0a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -13,7 +13,6 @@ import android.animation.Animator; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; @@ -38,7 +37,6 @@ import android.text.style.ClickableSpan; import android.util.Base64; import android.util.TypedValue; import android.view.Gravity; -import android.view.KeyEvent; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.inputmethod.EditorInfo; @@ -62,10 +60,10 @@ import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; +import org.telegram.messenger.SRPHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -76,6 +74,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.CheckBoxCell; +import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.HintEditText; import org.telegram.ui.Components.LayoutHelper; @@ -85,7 +84,6 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -215,6 +213,13 @@ public class LoginActivity extends BaseFragment { savedInstanceState = null; clearCurrentState(); } + } else if (currentViewNum == 6) { + LoginActivityPasswordView view = (LoginActivityPasswordView) views[6]; + if (view.passwordType == 0 || view.current_salt1 == null || view.current_salt2 == null) { + currentViewNum = 0; + savedInstanceState = null; + clearCurrentState(); + } } } actionBar.setTitle(views[currentViewNum].getHeaderName()); @@ -421,27 +426,24 @@ public class LoginActivity extends BaseFragment { } else { builder.setMessage(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } - builder.setNeutralButton(LocaleController.getString("BotHelp", R.string.BotHelp), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - try { - PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); + builder.setNeutralButton(LocaleController.getString("BotHelp", R.string.BotHelp), (dialog, which) -> { + try { + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); - mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"login@stel.com"}); - if (banned) { - mailer.putExtra(Intent.EXTRA_SUBJECT, "Banned phone number: " + phoneNumber); - mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's banned. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); - } else { - mailer.putExtra(Intent.EXTRA_SUBJECT, "Invalid phone number: " + phoneNumber); - mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's invalid. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); - } - getParentActivity().startActivity(Intent.createChooser(mailer, "Send email...")); - } catch (Exception e) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); + Intent mailer = new Intent(Intent.ACTION_SEND); + mailer.setType("message/rfc822"); + mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"login@stel.com"}); + if (banned) { + mailer.putExtra(Intent.EXTRA_SUBJECT, "Banned phone number: " + phoneNumber); + mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's banned. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); + } else { + mailer.putExtra(Intent.EXTRA_SUBJECT, "Invalid phone number: " + phoneNumber); + mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's invalid. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); } + getParentActivity().startActivity(Intent.createChooser(mailer, "Send email...")); + } catch (Exception e) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); @@ -455,13 +457,10 @@ public class LoginActivity extends BaseFragment { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), 1); builder.setMessage(LocaleController.getString("Loading", R.string.Loading)); if (reqiestId != 0) { - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - views[currentViewNum].onCancelPressed(); - ConnectionsManager.getInstance(currentAccount).cancelRequest(reqiestId, true); - progressDialog = null; - } + builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> { + views[currentViewNum].onCancelPressed(); + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqiestId, true); + progressDialog = null; }); } progressDialog = builder.show(); @@ -684,26 +683,15 @@ public class LoginActivity extends BaseFragment { countryButton.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL); countryButton.setBackgroundResource(R.drawable.spinner_states); addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 0, 14)); - countryButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - CountrySelectActivity fragment = new CountrySelectActivity(true); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - selectCountry(name, shortName); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AndroidUtilities.showKeyboard(phoneField); - } - }, 300); - phoneField.requestFocus(); - phoneField.setSelection(phoneField.length()); - } - }); - presentFragment(fragment); - } + countryButton.setOnClickListener(view -> { + CountrySelectActivity fragment = new CountrySelectActivity(true); + fragment.setCountrySelectActivityDelegate((name, shortName) -> { + selectCountry(name, shortName); + AndroidUtilities.runOnUIThread(() -> AndroidUtilities.showKeyboard(phoneField), 300); + phoneField.requestFocus(); + phoneField.setSelection(phoneField.length()); + }); + presentFragment(fragment); }); view = new View(context); @@ -811,16 +799,13 @@ public class LoginActivity extends BaseFragment { ignoreOnTextChange = false; } }); - codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - phoneField.requestFocus(); - phoneField.setSelection(phoneField.length()); - return true; - } - return false; + codeField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + phoneField.requestFocus(); + phoneField.setSelection(phoneField.length()); + return true; } + return false; }); phoneField = new HintEditText(context); @@ -911,15 +896,12 @@ public class LoginActivity extends BaseFragment { ignoreOnPhoneChange = false; } }); - phoneField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + phoneField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); textView2 = new TextView(context); @@ -983,12 +965,7 @@ public class LoginActivity extends BaseFragment { FileLog.e(e); } - Collections.sort(countriesArray, new Comparator() { - @Override - public int compare(String lhs, String rhs) { - return lhs.compareTo(rhs); - } - }); + Collections.sort(countriesArray, String::compareTo); String country = null; @@ -1145,14 +1122,11 @@ public class LoginActivity extends BaseFragment { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("AccountAlreadyLoggedIn", R.string.AccountAlreadyLoggedIn)); - builder.setPositiveButton(LocaleController.getString("AccountSwitch", R.string.AccountSwitch), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (UserConfig.selectedAccount != num) { - ((LaunchActivity) getParentActivity()).switchToAccount(num, false); - } - finishFragment(); + builder.setPositiveButton(LocaleController.getString("AccountSwitch", R.string.AccountSwitch), (dialog, which) -> { + if (UserConfig.selectedAccount != num) { + ((LaunchActivity) getParentActivity()).switchToAccount(num, false); } + finishFragment(); }); builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); showDialog(builder.create()); @@ -1198,41 +1172,33 @@ public class LoginActivity extends BaseFragment { } params.putString("phoneFormated", phone); nextPressed = true; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - nextPressed = false; - if (error == null) { - fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); - } else { - if (error.text != null) { - if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowInvalidAlert(req.phone_number, false); - } else if (error.text.contains("PHONE_PASSWORD_FLOOD")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); - } else if (error.text.contains("PHONE_NUMBER_FLOOD")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PhoneNumberFlood", R.string.PhoneNumberFlood)); - } else if (error.text.contains("PHONE_NUMBER_BANNED")) { - needShowInvalidAlert(req.phone_number, true); - } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); - } else if (error.text.contains("PHONE_CODE_EXPIRED")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); - } else if (error.code != -1000) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - needHideProgress(); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + if (error == null) { + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + } else { + if (error.text != null) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowInvalidAlert(req.phone_number, false); + } else if (error.text.contains("PHONE_PASSWORD_FLOOD")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.text.contains("PHONE_NUMBER_FLOOD")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PhoneNumberFlood", R.string.PhoneNumberFlood)); + } else if (error.text.contains("PHONE_NUMBER_BANNED")) { + needShowInvalidAlert(req.phone_number, true); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.code != -1000) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); } - }); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); + needHideProgress(); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); needShowProgress(reqId); } @@ -1313,18 +1279,15 @@ public class LoginActivity extends BaseFragment { if (checkBoxCell != null) { checkBoxCell.setChecked(syncContacts, false); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (phoneField != null) { - if (codeField.length() != 0) { - AndroidUtilities.showKeyboard(phoneField); - phoneField.requestFocus(); - phoneField.setSelection(phoneField.length()); - } else { - AndroidUtilities.showKeyboard(codeField); - codeField.requestFocus(); - } + AndroidUtilities.runOnUIThread(() -> { + if (phoneField != null) { + if (codeField.length() != 0) { + AndroidUtilities.showKeyboard(phoneField); + phoneField.requestFocus(); + phoneField.setSelection(phoneField.length()); + } else { + AndroidUtilities.showKeyboard(codeField); + codeField.requestFocus(); } } }, 100); @@ -1458,15 +1421,12 @@ public class LoginActivity extends BaseFragment { } } }); - codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + codeField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); if (currentType == 3) { codeField.setEnabled(false); @@ -1494,28 +1454,25 @@ public class LoginActivity extends BaseFragment { problemText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); problemText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(12)); addView(problemText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 20, 0, 0)); - problemText.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (nextPressed) { - return; - } - if (nextType != 0 && nextType != 4) { - resendCode(); - } else { - try { - PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); + problemText.setOnClickListener(v -> { + if (nextPressed) { + return; + } + if (nextType != 0 && nextType != 4) { + resendCode(); + } else { + try { + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); - mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); - mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); - mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); - getContext().startActivity(Intent.createChooser(mailer, "Send email...")); - } catch (Exception e) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); - } + Intent mailer = new Intent(Intent.ACTION_SEND); + mailer.setType("message/rfc822"); + mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); + mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); + mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); + getContext().startActivity(Intent.createChooser(mailer, "Send email...")); + } catch (Exception e) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); } } }); @@ -1532,21 +1489,15 @@ public class LoginActivity extends BaseFragment { wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0); linearLayout.addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 0, 0, 10)); wrongNumber.setText(LocaleController.getString("WrongNumber", R.string.WrongNumber)); - wrongNumber.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); - req.phone_number = requestPhone; - req.phone_code_hash = phoneHash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + wrongNumber.setOnClickListener(view -> { + TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - onBackPressed(); - setPage(0, true, null, true); - } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + onBackPressed(); + setPage(0, true, null, true); }); } @@ -1566,37 +1517,29 @@ public class LoginActivity extends BaseFragment { TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - nextPressed = false; - if (error == null) { - fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); - } else { - if (error.text != null) { - if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); - } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); - } else if (error.text.contains("PHONE_CODE_EXPIRED")) { - onBackPressed(); - setPage(0, true, null, true); - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); - } else if (error.code != -1000) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); - } - } - } - needHideProgress(); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + if (error == null) { + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + } else { + if (error.text != null) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + onBackPressed(); + setPage(0, true, null, true); + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.code != -1000) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); } - }); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + needHideProgress(); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); needShowProgress(0); } @@ -1722,13 +1665,10 @@ public class LoginActivity extends BaseFragment { double diff = currentTime - lastCodeTime; codeTime -= diff; lastCodeTime = currentTime; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (codeTime <= 1000) { - problemText.setVisibility(VISIBLE); - destroyCodeTimer(); - } + AndroidUtilities.runOnUIThread(() -> { + if (codeTime <= 1000) { + problemText.setVisibility(VISIBLE); + destroyCodeTimer(); } }); } @@ -1763,58 +1703,47 @@ public class LoginActivity extends BaseFragment { double diff = currentTime - lastCurrentTime; time -= diff; lastCurrentTime = currentTime; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (time >= 1000) { - int minutes = time / 1000 / 60; - int seconds = time / 1000 - minutes * 60; - if (nextType == 4 || nextType == 3) { - timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds)); - } else if (nextType == 2) { - timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, minutes, seconds)); - } - if (progressView != null) { - progressView.setProgress(1.0f - (float) time / (float) timeout); - } - } else { - if (progressView != null) { - progressView.setProgress(1.0f); - } - destroyTimer(); - if (currentType == 3) { - AndroidUtilities.setWaitingForCall(false); - NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveCall); + AndroidUtilities.runOnUIThread(() -> { + if (time >= 1000) { + int minutes = time / 1000 / 60; + int seconds = time / 1000 - minutes * 60; + if (nextType == 4 || nextType == 3) { + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds)); + } else if (nextType == 2) { + timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, minutes, seconds)); + } + if (progressView != null) { + progressView.setProgress(1.0f - (float) time / (float) timeout); + } + } else { + if (progressView != null) { + progressView.setProgress(1.0f); + } + destroyTimer(); + if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveCall); + waitingForEvent = false; + destroyCodeTimer(); + resendCode(); + } else if (currentType == 2) { + if (nextType == 4) { + timeText.setText(LocaleController.getString("Calling", R.string.Calling)); + createCodeTimer(); + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null && error.text != null) { + AndroidUtilities.runOnUIThread(() -> lastError = error.text); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else if (nextType == 3) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); waitingForEvent = false; destroyCodeTimer(); resendCode(); - } else if (currentType == 2) { - if (nextType == 4) { - timeText.setText(LocaleController.getString("Calling", R.string.Calling)); - createCodeTimer(); - TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); - req.phone_number = requestPhone; - req.phone_code_hash = phoneHash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error != null && error.text != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - lastError = error.text; - } - }); - } - } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - } else if (nextType == 3) { - AndroidUtilities.setWaitingForSms(false); - NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); - waitingForEvent = false; - destroyCodeTimer(); - resendCode(); - } } } } @@ -1856,103 +1785,100 @@ public class LoginActivity extends BaseFragment { req.phone_code = code; req.phone_code_hash = phoneHash; destroyTimer(); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - nextPressed = false; - boolean ok = false; - if (error == null) { - ok = true; - needHideProgress(); - destroyTimer(); - destroyCodeTimer(); - onAuthSuccess((TLRPC.TL_auth_authorization) response); - } else { - lastError = error.text; + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + boolean ok = false; + if (error == null) { + ok = true; + needHideProgress(); + destroyTimer(); + destroyCodeTimer(); + onAuthSuccess((TLRPC.TL_auth_authorization) response); + } else { + lastError = error.text; - if (error.text.contains("PHONE_NUMBER_UNOCCUPIED")) { - ok = true; - needHideProgress(); - Bundle params = new Bundle(); - params.putString("phoneFormated", requestPhone); - params.putString("phoneHash", phoneHash); - params.putString("code", req.phone_code); - setPage(5, true, params, false); - destroyTimer(); - destroyCodeTimer(); - } else if (error.text.contains("SESSION_PASSWORD_NEEDED")) { - ok = true; - TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req2, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - TLRPC.TL_account_password password = (TLRPC.TL_account_password) response; - Bundle bundle = new Bundle(); - bundle.putString("current_salt", Utilities.bytesToHex(password.current_salt)); - bundle.putString("hint", password.hint); - bundle.putString("email_unconfirmed_pattern", password.email_unconfirmed_pattern); - bundle.putString("phoneFormated", requestPhone); - bundle.putString("phoneHash", phoneHash); - bundle.putString("code", req.phone_code); - bundle.putInt("has_recovery", password.has_recovery ? 1 : 0); - setPage(6, true, bundle, false); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - }); - } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - destroyTimer(); - destroyCodeTimer(); - } else { - needHideProgress(); - if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && (nextType == 4 || nextType == 3)) { - createTimer(); - } - if (currentType == 2) { - AndroidUtilities.setWaitingForSms(true); - NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); - } else if (currentType == 3) { - AndroidUtilities.setWaitingForCall(true); - NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); - } - waitingForEvent = true; - if (currentType != 3) { - if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); - } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); - } else if (error.text.contains("PHONE_CODE_EXPIRED")) { - onBackPressed(); - setPage(0, true, null, true); - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); - } - } + if (error.text.contains("PHONE_NUMBER_UNOCCUPIED")) { + ok = true; + needHideProgress(); + Bundle params = new Bundle(); + params.putString("phoneFormated", requestPhone); + params.putString("phoneHash", phoneHash); + params.putString("code", req.phone_code); + setPage(5, true, params, false); + destroyTimer(); + destroyCodeTimer(); + } else if (error.text.contains("SESSION_PASSWORD_NEEDED")) { + ok = true; + TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error1 == null) { + TLRPC.TL_account_password password = (TLRPC.TL_account_password) response1; + if (!TwoStepVerificationActivity.canHandleCurrentPassword(password, true)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + return; } + Bundle bundle = new Bundle(); + if (password.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) password.current_algo; + bundle.putString("current_salt1", Utilities.bytesToHex(algo.salt1)); + bundle.putString("current_salt2", Utilities.bytesToHex(algo.salt2)); + bundle.putString("current_p", Utilities.bytesToHex(algo.p)); + bundle.putInt("current_g", algo.g); + bundle.putString("current_srp_B", Utilities.bytesToHex(password.srp_B)); + bundle.putLong("current_srp_id", password.srp_id); + bundle.putInt("passwordType", 1); + } + bundle.putString("hint", password.hint != null ? password.hint : ""); + bundle.putString("email_unconfirmed_pattern", password.email_unconfirmed_pattern != null ? password.email_unconfirmed_pattern : ""); + bundle.putString("phoneFormated", requestPhone); + bundle.putString("phoneHash", phoneHash); + bundle.putString("code", req.phone_code); + bundle.putInt("has_recovery", password.has_recovery ? 1 : 0); + setPage(6, true, bundle, false); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error1.text); } - if (ok) { - if (currentType == 3) { - AndroidUtilities.endIncomingCall(); - AndroidUtilities.removeLoginPhoneCall(code, true); - } + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + destroyTimer(); + destroyCodeTimer(); + } else { + needHideProgress(); + if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && (nextType == 4 || nextType == 3)) { + createTimer(); + } + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(true); + NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); + } + waitingForEvent = true; + if (currentType != 3) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + onBackPressed(); + setPage(0, true, null, true); + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); } } - }); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + if (ok) { + if (currentType == 3) { + AndroidUtilities.endIncomingCall(); + AndroidUtilities.removeLoginPhoneCall(code, true); + } + } + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); needShowProgress(0); } @@ -1992,13 +1918,10 @@ public class LoginActivity extends BaseFragment { if (currentType == 3) { return; } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (codeField != null) { - codeField.requestFocus(); - codeField.setSelection(codeField.length()); - } + AndroidUtilities.runOnUIThread(() -> { + if (codeField != null) { + codeField.requestFocus(); + codeField.setSelection(codeField.length()); } }, 100); } @@ -2085,7 +2008,13 @@ public class LoginActivity extends BaseFragment { private Bundle currentParams; private boolean nextPressed; - private byte[] current_salt; + private byte[] current_salt1; + private byte[] current_salt2; + private int current_g; + private long current_srp_id; + private byte[] current_srp_B; + private byte[] current_p; + private int passwordType; private String hint; private String email_unconfirmed_pattern; private boolean has_recovery; @@ -2123,15 +2052,12 @@ public class LoginActivity extends BaseFragment { codeField.setTypeface(Typeface.DEFAULT); codeField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0)); - codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + codeField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); cancelButton = new TextView(context); @@ -2142,61 +2068,47 @@ public class LoginActivity extends BaseFragment { cancelButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); cancelButton.setPadding(0, AndroidUtilities.dp(14), 0, 0); addView(cancelButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); - cancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (has_recovery) { - needShowProgress(0); - TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Bundle bundle = new Bundle(); - bundle.putString("email_unconfirmed_pattern", res.email_pattern); - setPage(7, true, bundle, false); - } - }); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } else { - if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + cancelButton.setOnClickListener(view -> { + if (has_recovery) { + needShowProgress(0); + TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error == null) { + final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + Bundle bundle = new Bundle(); + bundle.putString("email_unconfirmed_pattern", res.email_pattern); + setPage(7, true, bundle, false); + }); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - } else { - resetAccountText.setVisibility(VISIBLE); - resetAccountButton.setVisibility(VISIBLE); - AndroidUtilities.hideKeyboard(codeField); - needShowAlert(LocaleController.getString("RestorePasswordNoEitle", R.string.RestorePasswordNoEmailTitle), LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); - } + } else { + if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } + } + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + resetAccountText.setVisibility(VISIBLE); + resetAccountButton.setVisibility(VISIBLE); + AndroidUtilities.hideKeyboard(codeField); + needShowAlert(LocaleController.getString("RestorePasswordNoEitle", R.string.RestorePasswordNoEmailTitle), LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); } }); @@ -2210,55 +2122,41 @@ public class LoginActivity extends BaseFragment { resetAccountButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); resetAccountButton.setPadding(0, AndroidUtilities.dp(14), 0, 0); addView(resetAccountButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 34, 0, 0)); - resetAccountButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)); - builder.setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)); - builder.setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - needShowProgress(0); - TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); - req.reason = "Forgot password"; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - Bundle params = new Bundle(); - params.putString("phoneFormated", requestPhone); - params.putString("phoneHash", phoneHash); - params.putString("code", phoneCode); - setPage(5, true, params, false); - } else { - if (error.text.equals("2FA_RECENT_CONFIRM")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); - } else if (error.text.startsWith("2FA_CONFIRM_WAIT_")) { - Bundle params = new Bundle(); - params.putString("phoneFormated", requestPhone); - params.putString("phoneHash", phoneHash); - params.putString("code", phoneCode); - params.putInt("startTime", ConnectionsManager.getInstance(currentAccount).getCurrentTime()); - params.putInt("waitTime", Utilities.parseInt(error.text.replace("2FA_CONFIRM_WAIT_", ""))); - setPage(8, true, params, false); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); - } - }, ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); + resetAccountButton.setOnClickListener(view -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)); + builder.setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)); + builder.setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), (dialogInterface, i) -> { + needShowProgress(0); + TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); + req.reason = "Forgot password"; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error == null) { + Bundle params = new Bundle(); + params.putString("phoneFormated", requestPhone); + params.putString("phoneHash", phoneHash); + params.putString("code", phoneCode); + setPage(5, true, params, false); + } else { + if (error.text.equals("2FA_RECENT_CONFIRM")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); + } else if (error.text.startsWith("2FA_CONFIRM_WAIT_")) { + Bundle params = new Bundle(); + params.putString("phoneFormated", requestPhone); + params.putString("phoneHash", phoneHash); + params.putString("code", phoneCode); + params.putInt("startTime", ConnectionsManager.getInstance(currentAccount).getCurrentTime()); + params.putInt("waitTime", Utilities.parseInt(error.text.replace("2FA_CONFIRM_WAIT_", ""))); + setPage(8, true, params, false); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } + }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); resetAccountText = new TextView(context); @@ -2296,7 +2194,13 @@ public class LoginActivity extends BaseFragment { resetAccountText.setVisibility(GONE); codeField.setText(""); currentParams = params; - current_salt = Utilities.hexToBytes(currentParams.getString("current_salt")); + current_salt1 = Utilities.hexToBytes(currentParams.getString("current_salt1")); + current_salt2 = Utilities.hexToBytes(currentParams.getString("current_salt2")); + current_p = Utilities.hexToBytes(currentParams.getString("current_p")); + current_g = currentParams.getInt("current_g"); + current_srp_B = Utilities.hexToBytes(currentParams.getString("current_srp_B")); + current_srp_id = currentParams.getLong("current_srp_id"); + passwordType = currentParams.getInt("passwordType"); hint = currentParams.getString("hint"); has_recovery = currentParams.getInt("has_recovery") == 1; email_unconfirmed_pattern = currentParams.getString("email_unconfirmed_pattern"); @@ -2337,51 +2241,84 @@ public class LoginActivity extends BaseFragment { return; } nextPressed = true; - byte[] oldPasswordBytes = null; - try { - oldPasswordBytes = oldPassword.getBytes("UTF-8"); - } catch (Exception e) { - FileLog.e(e); - } - needShowProgress(0); - byte[] hash = new byte[current_salt.length * 2 + oldPasswordBytes.length]; - System.arraycopy(current_salt, 0, hash, 0, current_salt.length); - System.arraycopy(oldPasswordBytes, 0, hash, current_salt.length, oldPasswordBytes.length); - System.arraycopy(current_salt, 0, hash, hash.length - current_salt.length, current_salt.length); - final TLRPC.TL_auth_checkPassword req = new TLRPC.TL_auth_checkPassword(); - req.password_hash = Utilities.computeSHA256(hash, 0, hash.length); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - nextPressed = false; - if (error == null) { - onAuthSuccess((TLRPC.TL_auth_authorization) response); - } else { - if (error.text.equals("PASSWORD_HASH_INVALID")) { - onPasscodeError(true); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + Utilities.globalQueue.postRunnable(() -> { + final byte x_bytes[]; + + TLRPC.PasswordKdfAlgo current_algo = null; + if (passwordType == 1) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = new TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(); + algo.salt1 = current_salt1; + algo.salt2 = current_salt2; + algo.g = current_g; + algo.p = current_p; + current_algo = algo; } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + + if (current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + byte[] passwordBytes = AndroidUtilities.getStringBytes(oldPassword); + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) current_algo; + x_bytes = SRPHelper.getX(passwordBytes, algo); + } else { + x_bytes = null; + } + + + final TLRPC.TL_auth_checkPassword req = new TLRPC.TL_auth_checkPassword(); + + RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + TLRPC.TL_account_password password = (TLRPC.TL_account_password) response2; + current_srp_B = password.srp_B; + current_srp_id = password.srp_id; + onNextPressed(); + } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + needHideProgress(); + if (error == null) { + onAuthSuccess((TLRPC.TL_auth_authorization) response); + } else { + if (error.text.equals("PASSWORD_HASH_INVALID")) { + onPasscodeError(true); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } + } + }); + + if (current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) current_algo; + algo.salt1 = current_salt1; + algo.salt2 = current_salt2; + algo.g = current_g; + algo.p = current_p; + req.password = SRPHelper.startCheck(x_bytes, current_srp_id, current_srp_B, algo); + if (req.password == null) { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error); + return; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } + }); + } @Override @@ -2397,14 +2334,11 @@ public class LoginActivity extends BaseFragment { @Override public void onShow() { super.onShow(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (codeField != null) { - codeField.requestFocus(); - codeField.setSelection(codeField.length()); - AndroidUtilities.showKeyboard(codeField); - } + AndroidUtilities.runOnUIThread(() -> { + if (codeField != null) { + codeField.requestFocus(); + codeField.setSelection(codeField.length()); + AndroidUtilities.showKeyboard(codeField); } }, 100); } @@ -2483,50 +2417,36 @@ public class LoginActivity extends BaseFragment { resetAccountButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); resetAccountButton.setPadding(0, AndroidUtilities.dp(14), 0, 0); addView(resetAccountButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 7, 0, 0)); - resetAccountButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (Math.abs(ConnectionsManager.getInstance(currentAccount).getCurrentTime() - startTime) < waitTime) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)); - builder.setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)); - builder.setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - needShowProgress(0); - TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); - req.reason = "Forgot password"; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - Bundle params = new Bundle(); - params.putString("phoneFormated", requestPhone); - params.putString("phoneHash", phoneHash); - params.putString("code", phoneCode); - setPage(5, true, params, false); - } else { - if (error.text.equals("2FA_RECENT_CONFIRM")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); - } - }, ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + resetAccountButton.setOnClickListener(view -> { + if (Math.abs(ConnectionsManager.getInstance(currentAccount).getCurrentTime() - startTime) < waitTime) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)); + builder.setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)); + builder.setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), (dialogInterface, i) -> { + needShowProgress(0); + TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); + req.reason = "Forgot password"; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error == null) { + Bundle params = new Bundle(); + params.putString("phoneFormated", requestPhone); + params.putString("phoneHash", phoneHash); + params.putString("code", phoneCode); + setPage(5, true, params, false); + } else { + if (error.text.equals("2FA_RECENT_CONFIRM")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } + } + }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); } @@ -2649,15 +2569,12 @@ public class LoginActivity extends BaseFragment { codeField.setTypeface(Typeface.DEFAULT); codeField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0)); - codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + codeField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); cancelButton = new TextView(context); @@ -2667,23 +2584,15 @@ public class LoginActivity extends BaseFragment { cancelButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); cancelButton.setPadding(0, AndroidUtilities.dp(14), 0, 0); addView(cancelButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 0, 0, 14)); - cancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("RestoreEmailTroubleText", R.string.RestoreEmailTroubleText)); - builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - setPage(6, true, new Bundle(), true); - } - }); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } + cancelButton.setOnClickListener(view -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("RestoreEmailTroubleText", R.string.RestoreEmailTroubleText)); + builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> setPage(6, true, new Bundle(), true)); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); } }); } @@ -2752,36 +2661,28 @@ public class LoginActivity extends BaseFragment { needShowProgress(0); TLRPC.TL_auth_recoverPassword req = new TLRPC.TL_auth_recoverPassword(); req.code = code; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - nextPressed = false; - if (error == null) { - onAuthSuccess((TLRPC.TL_auth_authorization) response); - } else { - if (error.text.startsWith("CODE_INVALID")) { - onPasscodeError(true); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + nextPressed = false; + if (error == null) { + onAuthSuccess((TLRPC.TL_auth_authorization) response); + } else { + if (error.text.startsWith("CODE_INVALID")) { + onPasscodeError(true); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); } - }); + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } @Override @@ -2792,13 +2693,10 @@ public class LoginActivity extends BaseFragment { @Override public void onShow() { super.onShow(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (codeField != null) { - codeField.requestFocus(); - codeField.setSelection(codeField.length()); - } + AndroidUtilities.runOnUIThread(() -> { + if (codeField != null) { + codeField.requestFocus(); + codeField.setSelection(codeField.length()); } }, 100); } @@ -2861,34 +2759,20 @@ public class LoginActivity extends BaseFragment { builder.setTitle(LocaleController.getString("TermsOfService", R.string.TermsOfService)); if (needAccept) { - builder.setPositiveButton(LocaleController.getString("Accept", R.string.Accept), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { + builder.setPositiveButton(LocaleController.getString("Accept", R.string.Accept), (dialog, which) -> { + currentTermsOfService.popup = false; + onNextPressed(); + }); + builder.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), (dialog, which) -> { + AlertDialog.Builder builder1 = new AlertDialog.Builder(getParentActivity()); + builder1.setTitle(LocaleController.getString("TermsOfService", R.string.TermsOfService)); + builder1.setMessage(LocaleController.getString("TosDecline", R.string.TosDecline)); + builder1.setPositiveButton(LocaleController.getString("SignUp", R.string.SignUp), (dialog1, which1) -> { currentTermsOfService.popup = false; onNextPressed(); - } - }); - builder.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("TermsOfService", R.string.TermsOfService)); - builder.setMessage(LocaleController.getString("TosDecline", R.string.TosDecline)); - builder.setPositiveButton(LocaleController.getString("SignUp", R.string.SignUp), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - currentTermsOfService.popup = false; - onNextPressed(); - } - }); - builder.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - wrongNumber.callOnClick(); - } - }); - showDialog(builder.create()); - } + }); + builder1.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), (dialog12, which12) -> wrongNumber.callOnClick()); + showDialog(builder1.create()); }); } else { builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); @@ -2926,15 +2810,12 @@ public class LoginActivity extends BaseFragment { firstNameField.setMaxLines(1); firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS); addView(firstNameField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 26, 0, 0)); - firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - lastNameField.requestFocus(); - return true; - } - return false; + firstNameField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + lastNameField.requestFocus(); + return true; } + return false; }); lastNameField = new EditTextBoldCursor(context); @@ -2950,15 +2831,12 @@ public class LoginActivity extends BaseFragment { lastNameField.setMaxLines(1); lastNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS); addView(lastNameField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 10, 0, 0)); - lastNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + lastNameField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); wrongNumber = new TextView(context); @@ -2970,22 +2848,16 @@ public class LoginActivity extends BaseFragment { wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0); wrongNumber.setVisibility(GONE); addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 20, 0, 0)); - wrongNumber.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("AreYouSureRegistration", R.string.AreYouSureRegistration)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - onBackPressed(); - setPage(0, true, null, true); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } + wrongNumber.setOnClickListener(view -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("AreYouSureRegistration", R.string.AreYouSureRegistration)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + onBackPressed(); + setPage(0, true, null, true); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); privacyView = new TextView(context); @@ -3027,13 +2899,10 @@ public class LoginActivity extends BaseFragment { @Override public void onShow() { super.onShow(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (firstNameField != null) { - firstNameField.requestFocus(); - firstNameField.setSelection(firstNameField.length()); - } + AndroidUtilities.runOnUIThread(() -> { + if (firstNameField != null) { + firstNameField.requestFocus(); + firstNameField.setSelection(firstNameField.length()); } }, 100); } @@ -3068,35 +2937,27 @@ public class LoginActivity extends BaseFragment { req.first_name = firstNameField.getText().toString(); req.last_name = lastNameField.getText().toString(); needShowProgress(0); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - nextPressed = false; - needHideProgress(); - if (error == null) { - onAuthSuccess((TLRPC.TL_auth_authorization) response); - } else { - if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); - } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); - } else if (error.text.contains("PHONE_CODE_EXPIRED")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); - } else if (error.text.contains("FIRSTNAME_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidFirstName", R.string.InvalidFirstName)); - } else if (error.text.contains("LASTNAME_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidLastName", R.string.InvalidLastName)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + needHideProgress(); + if (error == null) { + onAuthSuccess((TLRPC.TL_auth_authorization) response); + } else { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.contains("FIRSTNAME_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidFirstName", R.string.InvalidFirstName)); + } else if (error.text.contains("LASTNAME_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidLastName", R.string.InvalidLastName)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + } } - }, ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index e616f370e..c9539189a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -14,7 +14,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; @@ -56,8 +55,6 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; @@ -406,13 +403,10 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - deleteForAll[0] = !deleteForAll[0]; - cell.setChecked(deleteForAll[0], true); - } + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + deleteForAll[0] = !deleteForAll[0]; + cell1.setChecked(deleteForAll[0], true); }); builder.setView(frameLayout); } @@ -420,42 +414,39 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - for (int a = 1; a >= 0; a--) { - ArrayList ids = new ArrayList<>(); - for (int b = 0; b < selectedFiles[a].size(); b++) { - ids.add(selectedFiles[a].keyAt(b)); - } - ArrayList random_ids = null; - TLRPC.EncryptedChat currentEncryptedChat = null; - int channelId = 0; - if (!ids.isEmpty()) { - MessageObject msg = selectedFiles[a].get(ids.get(0)); - if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { - channelId = msg.messageOwner.to_id.channel_id; - } - } - if ((int) dialog_id == 0) { - currentEncryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat((int) (dialog_id >> 32)); - } - if (currentEncryptedChat != null) { - random_ids = new ArrayList<>(); - for (int b = 0; b < selectedFiles[a].size(); b++) { - MessageObject msg = selectedFiles[a].valueAt(b); - if (msg.messageOwner.random_id != 0 && msg.type != 10) { - random_ids.add(msg.messageOwner.random_id); - } - } - } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, channelId, deleteForAll[0]); - selectedFiles[a].clear(); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + for (int a = 1; a >= 0; a--) { + ArrayList ids = new ArrayList<>(); + for (int b = 0; b < selectedFiles[a].size(); b++) { + ids.add(selectedFiles[a].keyAt(b)); } - actionBar.hideActionMode(); - actionBar.closeSearchField(); - cantDeleteMessagesCount = 0; + ArrayList random_ids = null; + TLRPC.EncryptedChat currentEncryptedChat = null; + int channelId = 0; + if (!ids.isEmpty()) { + MessageObject msg = selectedFiles[a].get(ids.get(0)); + if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { + channelId = msg.messageOwner.to_id.channel_id; + } + } + if ((int) dialog_id == 0) { + currentEncryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat((int) (dialog_id >> 32)); + } + if (currentEncryptedChat != null) { + random_ids = new ArrayList<>(); + for (int b = 0; b < selectedFiles[a].size(); b++) { + MessageObject msg = selectedFiles[a].valueAt(b); + if (msg.messageOwner.random_id != 0 && msg.type != 10) { + random_ids.add(msg.messageOwner.random_id); + } + } + } + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, currentEncryptedChat, channelId, deleteForAll[0]); + selectedFiles[a].clear(); } + actionBar.hideActionMode(); + actionBar.closeSearchField(); + cantDeleteMessagesCount = 0; }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -464,65 +455,62 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - ArrayList fmessages = new ArrayList<>(); - for (int a = 1; a >= 0; a--) { - ArrayList ids = new ArrayList<>(); - for (int b = 0; b < selectedFiles[a].size(); b++) { - ids.add(selectedFiles[a].keyAt(b)); - } - Collections.sort(ids); - for (Integer id : ids) { - if (id > 0) { - fmessages.add(selectedFiles[a].get(id)); - } - } - selectedFiles[a].clear(); + fragment.setDelegate((fragment1, dids, message, param) -> { + ArrayList fmessages = new ArrayList<>(); + for (int a = 1; a >= 0; a--) { + ArrayList ids = new ArrayList<>(); + for (int b = 0; b < selectedFiles[a].size(); b++) { + ids.add(selectedFiles[a].keyAt(b)); } - cantDeleteMessagesCount = 0; - actionBar.hideActionMode(); - - if (dids.size() > 1 || dids.get(0) == UserConfig.getInstance(currentAccount).getClientUserId() || message != null) { - for (int a = 0; a < dids.size(); a++) { - long did = dids.get(a); - if (message != null) { - SendMessagesHelper.getInstance(currentAccount).sendMessage(message.toString(), did, null, null, true, null, null, null); - } - SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessages, did); + Collections.sort(ids); + for (Integer id1 : ids) { + if (id1 > 0) { + fmessages.add(selectedFiles[a].get(id1)); + } + } + selectedFiles[a].clear(); + } + cantDeleteMessagesCount = 0; + actionBar.hideActionMode(); + + if (dids.size() > 1 || dids.get(0) == UserConfig.getInstance(currentAccount).getClientUserId() || message != null) { + for (int a = 0; a < dids.size(); a++) { + long did = dids.get(a); + if (message != null) { + SendMessagesHelper.getInstance(currentAccount).sendMessage(message.toString(), did, null, null, true, null, null, null); + } + SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessages, did); + } + fragment1.finishFragment(); + } else { + long did = dids.get(0); + int lower_part = (int) did; + int high_part = (int) (did >> 32); + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + if (lower_part != 0) { + if (lower_part > 0) { + args1.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args1.putInt("chat_id", -lower_part); } - fragment.finishFragment(); } else { - long did = dids.get(0); - int lower_part = (int) did; - int high_part = (int) (did >> 32); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - if (lower_part != 0) { - if (lower_part > 0) { - args.putInt("user_id", lower_part); - } else if (lower_part < 0) { - args.putInt("chat_id", -lower_part); - } - } else { - args.putInt("enc_id", high_part); - } - if (lower_part != 0) { - if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, fragment)) { - return; - } + args1.putInt("enc_id", high_part); + } + if (lower_part != 0) { + if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { + return; } + } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - ChatActivity chatActivity = new ChatActivity(args); - presentFragment(chatActivity, true); - chatActivity.showFieldPanelForForward(true, fmessages); + ChatActivity chatActivity = new ChatActivity(args1); + presentFragment(chatActivity, true); + chatActivity.showFieldPanelForForward(true, fmessages); - if (!AndroidUtilities.isTablet()) { - removeSelfFromStack(); - } + if (!AndroidUtilities.isTablet()) { + removeSelfFromStack(); } } }); @@ -671,12 +659,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No selectedMessagesCountTextView.setTextSize(18); selectedMessagesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); selectedMessagesCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultIcon)); - selectedMessagesCountTextView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + selectedMessagesCountTextView.setOnTouchListener((v, event) -> true); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); if ((int) dialog_id != 0) { @@ -925,16 +908,13 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No mediaPages[a].listView.setSectionsType(2); mediaPages[a].listView.setLayoutManager(layoutManager); mediaPages[a].addView(mediaPages[a].listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - mediaPages[a].listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (mediaPage.selectedType == 1 && view instanceof SharedDocumentCell) { - MediaActivity.this.onItemClick(position, view, ((SharedDocumentCell) view).getMessage(), 0, mediaPage.selectedType); - } else if (mediaPage.selectedType == 3 && view instanceof SharedLinkCell) { - MediaActivity.this.onItemClick(position, view, ((SharedLinkCell) view).getMessage(), 0, mediaPage.selectedType); - } else if ((mediaPage.selectedType == 2 || mediaPage.selectedType == 4) && view instanceof SharedAudioCell) { - MediaActivity.this.onItemClick(position, view, ((SharedAudioCell) view).getMessage(), 0, mediaPage.selectedType); - } + mediaPages[a].listView.setOnItemClickListener((view, position) -> { + if (mediaPage.selectedType == 1 && view instanceof SharedDocumentCell) { + MediaActivity.this.onItemClick(position, view, ((SharedDocumentCell) view).getMessage(), 0, mediaPage.selectedType); + } else if (mediaPage.selectedType == 3 && view instanceof SharedLinkCell) { + MediaActivity.this.onItemClick(position, view, ((SharedLinkCell) view).getMessage(), 0, mediaPage.selectedType); + } else if ((mediaPage.selectedType == 2 || mediaPage.selectedType == 4) && view instanceof SharedAudioCell) { + MediaActivity.this.onItemClick(position, view, ((SharedAudioCell) view).getMessage(), 0, mediaPage.selectedType); } }); mediaPages[a].listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -978,18 +958,15 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } } }); - mediaPages[a].listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (mediaPage.selectedType == 1 && view instanceof SharedDocumentCell) { - return MediaActivity.this.onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); - } else if (mediaPage.selectedType == 3 && view instanceof SharedLinkCell) { - return MediaActivity.this.onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); - } else if ((mediaPage.selectedType == 2 || mediaPage.selectedType == 4) && view instanceof SharedAudioCell) { - return MediaActivity.this.onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); - } - return false; + mediaPages[a].listView.setOnItemLongClickListener((view, position) -> { + if (mediaPage.selectedType == 1 && view instanceof SharedDocumentCell) { + return MediaActivity.this.onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); + } else if (mediaPage.selectedType == 3 && view instanceof SharedLinkCell) { + return MediaActivity.this.onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); + } else if ((mediaPage.selectedType == 2 || mediaPage.selectedType == 4) && view instanceof SharedAudioCell) { + return MediaActivity.this.onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); } + return false; }); if (a == 0 && scrollToPositionOnRecreate != -1) { layoutManager.scrollToPositionWithOffset(scrollToPositionOnRecreate, scrollToOffsetOnRecreate); @@ -1001,12 +978,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No mediaPages[a].emptyView.setVisibility(View.GONE); mediaPages[a].emptyView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); mediaPages[a].addView(mediaPages[a].emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - mediaPages[a].emptyView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + mediaPages[a].emptyView.setOnTouchListener((v, event) -> true); mediaPages[a].emptyImageView = new ImageView(context); mediaPages[a].emptyView.addView(mediaPages[a].emptyImageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); @@ -1799,20 +1771,17 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No public void onLinkLongPress(final String urlFinal) { BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); builder.setTitle(urlFinal); - builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, final int which) { - if (which == 0) { - Browser.openUrl(getParentActivity(), urlFinal, true); - } else if (which == 1) { - String url = urlFinal; - if (url.startsWith("mailto:")) { - url = url.substring(7); - } else if (url.startsWith("tel:")) { - url = url.substring(4); - } - AndroidUtilities.addToClipboard(url); + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { + if (which == 0) { + Browser.openUrl(getParentActivity(), urlFinal, true); + } else if (which == 1) { + String url = urlFinal; + if (url.startsWith("mailto:")) { + url = url.substring(7); + } else if (url.startsWith("tel:")) { + url = url.substring(4); } + AndroidUtilities.addToClipboard(url); } }); showDialog(builder.create()); @@ -2267,34 +2236,28 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } final int currentReqId = ++lastReqId; searchesInProgress++; - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - final ArrayList messageObjects = new ArrayList<>(); - if (error == null) { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - for (int a = 0; a < res.messages.size(); a++) { - TLRPC.Message message = res.messages.get(a); - if (max_id != 0 && message.id > max_id) { - continue; - } - messageObjects.add(new MessageObject(currentAccount, message, false)); + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + final ArrayList messageObjects = new ArrayList<>(); + if (error == null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + if (max_id != 0 && message.id > max_id) { + continue; } + messageObjects.add(new MessageObject(currentAccount, message, false)); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (reqId != 0) { - if (currentReqId == lastReqId) { - globalSearch = messageObjects; - searchesInProgress--; - notifyDataSetChanged(); - } - reqId = 0; - } - } - }); } + AndroidUtilities.runOnUIThread(() -> { + if (reqId != 0) { + if (currentReqId == lastReqId) { + globalSearch = messageObjects; + searchesInProgress--; + notifyDataSetChanged(); + } + reqId = 0; + } + }); }, ConnectionsManager.RequestFlagFailOnServerErrors); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -2349,95 +2312,86 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } private void processSearch(final String query) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!sharedMediaData[currentType].messages.isEmpty() && (currentType == 1 || currentType == 4)) { - MessageObject messageObject = sharedMediaData[currentType].messages.get(sharedMediaData[currentType].messages.size() - 1); - queryServerSearch(query, messageObject.getId(), messageObject.getDialogId()); - } else if (currentType == 3) { - queryServerSearch(query, 0, dialog_id); - } - if (currentType == 1 || currentType == 4) { - final ArrayList copy = new ArrayList<>(sharedMediaData[currentType].messages); - searchesInProgress++; - Utilities.searchQueue.postRunnable(new Runnable() { - @Override - public void run() { - String search1 = query.trim().toLowerCase(); - if (search1.length() == 0) { - updateSearchResults(new ArrayList()); - return; - } - String search2 = LocaleController.getInstance().getTranslitString(search1); - if (search1.equals(search2) || search2.length() == 0) { - search2 = null; - } - String search[] = new String[1 + (search2 != null ? 1 : 0)]; - search[0] = search1; - if (search2 != null) { - search[1] = search2; - } + AndroidUtilities.runOnUIThread(() -> { + if (!sharedMediaData[currentType].messages.isEmpty() && (currentType == 1 || currentType == 4)) { + MessageObject messageObject = sharedMediaData[currentType].messages.get(sharedMediaData[currentType].messages.size() - 1); + queryServerSearch(query, messageObject.getId(), messageObject.getDialogId()); + } else if (currentType == 3) { + queryServerSearch(query, 0, dialog_id); + } + if (currentType == 1 || currentType == 4) { + final ArrayList copy = new ArrayList<>(sharedMediaData[currentType].messages); + searchesInProgress++; + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } - ArrayList resultArray = new ArrayList<>(); + ArrayList resultArray = new ArrayList<>(); - for (int a = 0; a < copy.size(); a++) { - MessageObject messageObject = copy.get(a); - for (int b = 0; b < search.length; b++) { - String q = search[b]; - String name = messageObject.getDocumentName(); - if (name == null || name.length() == 0) { - continue; - } - name = name.toLowerCase(); - if (name.contains(q)) { - resultArray.add(messageObject); + for (int a = 0; a < copy.size(); a++) { + MessageObject messageObject = copy.get(a); + for (int b = 0; b < search.length; b++) { + String q = search[b]; + String name = messageObject.getDocumentName(); + if (name == null || name.length() == 0) { + continue; + } + name = name.toLowerCase(); + if (name.contains(q)) { + resultArray.add(messageObject); + break; + } + if (currentType == 4) { + TLRPC.Document document; + if (messageObject.type == 0) { + document = messageObject.messageOwner.media.webpage.document; + } else { + document = messageObject.messageOwner.media.document; + } + boolean ok = false; + for (int c = 0; c < document.attributes.size(); c++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(c); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.performer != null) { + ok = attribute.performer.toLowerCase().contains(q); + } + if (!ok && attribute.title != null) { + ok = attribute.title.toLowerCase().contains(q); + } break; } - if (currentType == 4) { - TLRPC.Document document; - if (messageObject.type == 0) { - document = messageObject.messageOwner.media.webpage.document; - } else { - document = messageObject.messageOwner.media.document; - } - boolean ok = false; - for (int c = 0; c < document.attributes.size(); c++) { - TLRPC.DocumentAttribute attribute = document.attributes.get(c); - if (attribute instanceof TLRPC.TL_documentAttributeAudio) { - if (attribute.performer != null) { - ok = attribute.performer.toLowerCase().contains(q); - } - if (!ok && attribute.title != null) { - ok = attribute.title.toLowerCase().contains(q); - } - break; - } - } - if (ok) { - resultArray.add(messageObject); - break; - } - } + } + if (ok) { + resultArray.add(messageObject); + break; } } - - updateSearchResults(resultArray); } - }); - } + } + + updateSearchResults(resultArray); + }); } }); } private void updateSearchResults(final ArrayList documents) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - searchesInProgress--; - searchResult = documents; - notifyDataSetChanged(); - } + AndroidUtilities.runOnUIThread(() -> { + searchesInProgress--; + searchResult = documents; + notifyDataSetChanged(); }); } @@ -2591,16 +2545,13 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No for (int a = 0; a < mediaPages.length; a++) { final int num = a; - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (mediaPages[num].listView != null) { - int count = mediaPages[num].listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = mediaPages[num].listView.getChildAt(a); - if (child instanceof SharedPhotoVideoCell) { - ((SharedPhotoVideoCell) child).updateCheckboxColor(); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (mediaPages[num].listView != null) { + int count = mediaPages[num].listView.getChildCount(); + for (int a1 = 0; a1 < count; a1++) { + View child = mediaPages[num].listView.getChildAt(a1); + if (child instanceof SharedPhotoVideoCell) { + ((SharedPhotoVideoCell) child).updateCheckboxColor(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsExceptionsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsExceptionsActivity.java new file mode 100644 index 000000000..9b666a041 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsExceptionsActivity.java @@ -0,0 +1,597 @@ +/* + * This is the source code of Telegram for Android v. 4.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-2018. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.support.widget.LinearLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +public class NotificationsExceptionsActivity extends BaseFragment { + + ArrayList exceptions; + + private ListAdapter listViewAdapter; + private EmptyTextProgressView emptyView; + private RecyclerListView listView; + private SearchAdapter searchListViewAdapter; + + private boolean searchWas; + private boolean searching; + + private final static int search_button = 0; + + public NotificationsExceptionsActivity(ArrayList arrayList) { + super(); + exceptions = arrayList; + } + + @Override + public View createView(Context context) { + searching = false; + searchWas = false; + + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setTitle(LocaleController.getString("NotificationsExceptions", R.string.NotificationsExceptions)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + searchListViewAdapter = new SearchAdapter(context); + ActionBarMenu menu = actionBar.createMenu(); + ActionBarMenuItem searchItem = menu.addItem(search_button, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + @Override + public void onSearchExpand() { + searching = true; + emptyView.setShowAtCenter(true); + } + + @Override + public void onSearchCollapse() { + searchListViewAdapter.searchDialogs(null); + searching = false; + searchWas = false; + emptyView.setText(LocaleController.getString("NoExceptions", R.string.NoExceptions)); + listView.setAdapter(listViewAdapter); + listViewAdapter.notifyDataSetChanged(); + listView.setFastScrollVisible(true); + listView.setVerticalScrollBarEnabled(false); + emptyView.setShowAtCenter(false); + } + + @Override + public void onTextChanged(EditText editText) { + if (searchListViewAdapter == null) { + return; + } + String text = editText.getText().toString(); + if (text.length() != 0) { + searchWas = true; + if (listView != null) { + emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + listView.setAdapter(searchListViewAdapter); + searchListViewAdapter.notifyDataSetChanged(); + listView.setFastScrollVisible(false); + listView.setVerticalScrollBarEnabled(true); + } + } + searchListViewAdapter.searchDialogs(text); + } + }); + searchItem.getSearchField().setHint(LocaleController.getString("Search", R.string.Search)); + + fragmentView = new FrameLayout(context); + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + emptyView = new EmptyTextProgressView(context); + emptyView.setTextSize(18); + emptyView.setText(LocaleController.getString("NoExceptions", R.string.NoExceptions)); + emptyView.showTextView(); + frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + listView = new RecyclerListView(context); + listView.setEmptyView(emptyView); + listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + listView.setAdapter(listViewAdapter = new ListAdapter(context)); + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + listView.setOnItemClickListener((view, position) -> { + ArrayList arrayList; + if (listView.getAdapter() == searchListViewAdapter) { + arrayList = searchListViewAdapter.searchResult; + } else { + arrayList = exceptions; + } + if (position < 0 || position >= arrayList.size()) { + return; + } + NotificationsSettingsActivity.NotificationException exception = arrayList.get(position); + AlertsCreator.showCustomNotificationsDialog(NotificationsExceptionsActivity.this, exception.did, currentAccount, param -> { + if (param == 0) { + if (arrayList != exceptions) { + int index = exceptions.indexOf(exception); + if (index >= 0) { + exceptions.remove(index); + listViewAdapter.notifyItemRemoved(index); + } + } + arrayList.remove(exception); + if (arrayList.isEmpty() && arrayList == exceptions) { + listView.getAdapter().notifyItemRemoved(1); + } + listView.getAdapter().notifyItemRemoved(position); + } else { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + exception.hasCustom = preferences.getBoolean("custom_" + exception.did, false); + exception.notify = preferences.getInt("notify2_" + exception.did, 0); + if (exception.notify != 0) { + int time = preferences.getInt("notifyuntil_" + exception.did, -1); + if (time != -1) { + exception.muteUntil = time; + } + } + listView.getAdapter().notifyItemChanged(position); + } + }); + }); + + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING && searching && searchWas) { + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); + } + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + } + }); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + + private class SearchAdapter extends RecyclerListView.SelectionAdapter { + + private Context mContext; + private ArrayList searchResult = new ArrayList<>(); + private ArrayList searchResultNames = new ArrayList<>(); + private Timer searchTimer; + + public SearchAdapter(Context context) { + mContext = context; + } + + public void searchDialogs(final String query) { + try { + if (searchTimer != null) { + searchTimer.cancel(); + } + } catch (Exception e) { + FileLog.e(e); + } + if (query == null) { + searchResult.clear(); + searchResultNames.clear(); + notifyDataSetChanged(); + } else { + searchTimer = new Timer(); + searchTimer.schedule(new TimerTask() { + @Override + public void run() { + try { + searchTimer.cancel(); + searchTimer = null; + } catch (Exception e) { + FileLog.e(e); + } + processSearch(query); + } + }, 200, 300); + } + } + + private void processSearch(final String query) { + AndroidUtilities.runOnUIThread(() -> { + final ArrayList contactsCopy = new ArrayList<>(exceptions); + Utilities.searchQueue.postRunnable(() -> { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList<>(), new ArrayList<>()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } + + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); + + String names[] = new String[2]; + for (int a = 0; a < contactsCopy.size(); a++) { + NotificationsSettingsActivity.NotificationException exception = contactsCopy.get(a); + + int lower_id = (int) exception.did; + int high_id = (int) (exception.did >> 32); + + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user != null) { + names[0] = ContactsController.formatName(user.first_name, user.last_name); + names[1] = user.username; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat != null) { + if (chat.left || chat.kicked || chat.migrated_to != null) { + continue; + } + names[0] = chat.title; + names[1] = chat.username; + } + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user != null) { + names[0] = ContactsController.formatName(user.first_name, user.last_name); + names[1] = user.username; + } + } + } + + String originalName = names[0]; + names[0] = names[0].toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(names[0]); + if (names[0] != null && names[0].equals(tName)) { + tName = null; + } + + int found = 0; + for (int b = 0; b < search.length; b++) { + String q = search[b]; + if (names[0] != null && (names[0].startsWith(q) || names[0].contains(" " + q)) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (names[1] != null && names[1].startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(originalName, null, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + names[1], null, "@" + q)); + } + resultArray.add(exception); + break; + } + } + } + updateSearchResults(resultArray, resultArrayNames); + }); + }); + } + + private void updateSearchResults(final ArrayList users, final ArrayList names) { + AndroidUtilities.runOnUIThread(() -> { + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); + }); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + @Override + public int getItemCount() { + return searchResult.size(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = new ProfileSearchCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; + + NotificationsSettingsActivity.NotificationException exception = searchResult.get(position); + int lower_id = (int) exception.did; + int high_id = (int) (exception.did >> 32); + + String un = null; + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user != null) { + un = user.username; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat != null) { + un = chat.username; + } + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user != null) { + un = user.username; + } + } + } + + CharSequence name = searchResultNames.get(position); + CharSequence username = null; + if (name != null && un != null && un.length() > 0) { + if (name.toString().startsWith("@" + un)) { + username = name; + name = null; + } + } + + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user != null) { + cell.setData(user, null, name, username, false, false); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat != null) { + cell.setData(chat, null, name, username, false, false); + } + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user != null) { + cell.setData(user, encryptedChat, name, username, false, false); + } + } + } + } + + @Override + public int getItemViewType(int i) { + return 0; + } + } + + private class ListAdapter extends RecyclerListView.SelectionAdapter { + + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + int type = holder.getItemViewType(); + return type == 0 || type == 2 || type == 6; + } + + @Override + public int getItemCount() { + return exceptions.isEmpty() ? 0 : exceptions.size() + 1; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case 0: + view = new ProfileSearchCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 1: + default: + view = new ShadowSectionCell(mContext); + view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case 0: + ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; + NotificationsSettingsActivity.NotificationException exception = exceptions.get(position); + + String text; + boolean enabled; + boolean custom = exception.hasCustom; + int value = exception.notify; + int delta = exception.muteUntil; + if (value == 3 && delta != Integer.MAX_VALUE) { + delta -= ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + if (delta <= 0) { + if (custom) { + text = LocaleController.getString("NotificationsCustom", R.string.NotificationsCustom); + } else { + text = LocaleController.getString("NotificationsUnmuted", R.string.NotificationsUnmuted); + } + } else if (delta < 60 * 60) { + text = LocaleController.formatString("WillUnmuteIn", R.string.WillUnmuteIn, LocaleController.formatPluralString("Minutes", delta / 60)); + } else if (delta < 60 * 60 * 24) { + text = LocaleController.formatString("WillUnmuteIn", R.string.WillUnmuteIn, LocaleController.formatPluralString("Hours", (int) Math.ceil(delta / 60.0f / 60))); + } else if (delta < 60 * 60 * 24 * 365) { + text = LocaleController.formatString("WillUnmuteIn", R.string.WillUnmuteIn, LocaleController.formatPluralString("Days", (int) Math.ceil(delta / 60.0f / 60 / 24))); + } else { + text = null; + } + } else { + if (value == 0) { + enabled = true; + } else if (value == 1) { + enabled = true; + } else if (value == 2) { + enabled = false; + } else { + enabled = false; + } + if (enabled && custom) { + text = LocaleController.getString("NotificationsCustom", R.string.NotificationsCustom); + } else { + text = enabled ? LocaleController.getString("NotificationsUnmuted", R.string.NotificationsUnmuted) : LocaleController.getString("NotificationsMuted", R.string.NotificationsMuted); + } + } + if (text == null) { + text = LocaleController.getString("NotificationsOff", R.string.NotificationsOff); + } + + int lower_id = (int) exception.did; + int high_id = (int) (exception.did >> 32); + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user != null) { + cell.setData(user, null, null, text, false, false); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat != null) { + cell.setData(chat, null, null, text, false, false); + } + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user != null) { + cell.setData(user, encryptedChat, null, text, false, false); + } + } + } + break; + } + } + + @Override + public int getItemViewType(int position) { + if (position >= 0 && position < exceptions.size()) { + return 0; + } + return 1; + } + } + + @Override + public ThemeDescription[] getThemeDescriptions() { + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof ProfileSearchCell) { + ((ProfileSearchCell) child).update(0); + } + } + } + }; + + return new ThemeDescription[]{ + new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{ProfileSearchCell.class}, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray), + + new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault), + new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle), + new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector), + + new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector), + + new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider), + + new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow), + + new ThemeDescription(listView, 0, new Class[]{ProfileSearchCell.class}, Theme.dialogs_namePaint, null, null, Theme.key_chats_name), + new ThemeDescription(listView, 0, new Class[]{ProfileSearchCell.class}, Theme.dialogs_nameEncryptedPaint, null, null, Theme.key_chats_secretName), + new ThemeDescription(listView, 0, new Class[]{ProfileSearchCell.class}, null, new Drawable[]{Theme.dialogs_lockDrawable}, null, Theme.key_chats_secretIcon), + new ThemeDescription(listView, 0, new Class[]{ProfileSearchCell.class}, null, new Drawable[]{Theme.dialogs_groupDrawable, Theme.dialogs_broadcastDrawable, Theme.dialogs_botDrawable}, null, Theme.key_chats_nameIcon), + new ThemeDescription(listView, 0, new Class[]{ProfileSearchCell.class}, Theme.dialogs_offlinePaint, null, null, Theme.key_windowBackgroundWhiteGrayText3), + + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundOrange), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundViolet), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundGreen), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundCyan), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundBlue), + new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink), + }; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index 0ed0309fe..cb3846cd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -10,7 +10,6 @@ package org.telegram.ui; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.media.Ringtone; @@ -18,21 +17,25 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; +import android.text.TextUtils; +import android.util.LongSparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.Toast; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.FileLog; import org.telegram.messenger.MessagesController; @@ -52,11 +55,23 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import java.util.ArrayList; +import java.util.Map; + public class NotificationsSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + public static class NotificationException { + public int muteUntil; + public boolean hasCustom; + public int notify; + public long did; + } + private RecyclerListView listView; private boolean reseting = false; private ListAdapter adapter; + private ArrayList exceptionUsers = null; + private ArrayList exceptionChats = null; private int notificationsServiceRow; private int notificationsServiceConnectionRow; @@ -68,6 +83,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif private int messageLedRow; private int messagePopupNotificationRow; private int messagePriorityRow; + private int messageExceptionsRow; private int groupSectionRow2; private int groupSectionRow; private int groupAlertRow; @@ -77,6 +93,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif private int groupLedRow; private int groupPopupNotificationRow; private int groupPriorityRow; + private int groupExceptionsRow; private int inappSectionRow2; private int inappSectionRow; private int inappSoundRow; @@ -104,6 +121,127 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif @Override public boolean onFragmentCreate() { + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + ArrayList usersResult = new ArrayList<>(); + ArrayList chatsResult = new ArrayList<>(); + LongSparseArray waitingForLoadExceptions = new LongSparseArray<>(); + + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedChatsToLoad = new ArrayList<>(); + + ArrayList users = new ArrayList<>(); + ArrayList chats = new ArrayList<>(); + ArrayList encryptedChats = new ArrayList<>(); + int selfId = UserConfig.getInstance(currentAccount).clientUserId; + + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + Map values = preferences.getAll(); + for (Map.Entry entry : values.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("notify2_")) { + key = key.replace("notify2_", ""); + + long did = Utilities.parseLong(key); + if (did != 0 && did != selfId) { + NotificationException exception = new NotificationException(); + exception.did = did; + exception.hasCustom = preferences.getBoolean("custom_" + did, false); + exception.notify = (Integer) entry.getValue(); + if (exception.notify != 0) { + Integer time = (Integer) values.get("notifyuntil_" + key); + if (time != null) { + exception.muteUntil = time; + } + } + + int lower_id = (int) did; + int high_id = (int) (did << 32); + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user == null) { + usersToLoad.add(lower_id); + waitingForLoadExceptions.put(did, exception); + } + usersResult.add(exception); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat == null) { + chatsToLoad.add(-lower_id); + waitingForLoadExceptions.put(did, exception); + } else if (chat.left || chat.kicked || chat.migrated_to != null) { + continue; + } + chatsResult.add(exception); + } + } else if (high_id != 0) { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat == null) { + encryptedChatsToLoad.add(high_id); + waitingForLoadExceptions.put(did, exception); + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user == null) { + usersToLoad.add(encryptedChat.user_id); + waitingForLoadExceptions.put(encryptedChat.user_id, exception); + } + } + usersResult.add(exception); + } + } + } + } + if (waitingForLoadExceptions.size() != 0) { + try { + if (!encryptedChatsToLoad.isEmpty()) { + MessagesStorage.getInstance(currentAccount).getEncryptedChatsInternal(TextUtils.join(",", encryptedChatsToLoad), encryptedChats, usersToLoad); + } + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance(currentAccount).getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance(currentAccount).getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + } catch (Exception e) { + FileLog.e(e); + } + for (int a = 0, size = chats.size(); a < size; a++) { + TLRPC.Chat chat = chats.get(a); + if (chat.left || chat.kicked || chat.migrated_to != null) { + continue; + } + waitingForLoadExceptions.remove(-chat.id); + } + for (int a = 0, size = users.size(); a < size; a++) { + TLRPC.User user = users.get(a); + waitingForLoadExceptions.remove(user.id); + } + for (int a = 0, size = encryptedChats.size(); a < size; a++) { + TLRPC.EncryptedChat encryptedChat = encryptedChats.get(a); + waitingForLoadExceptions.remove(((long) encryptedChat.id) << 32); + } + for (int a = 0, size = waitingForLoadExceptions.size(); a < size; a++) { + long did = waitingForLoadExceptions.keyAt(a); + if ((int) did < 0) { + chatsResult.remove(waitingForLoadExceptions.valueAt(a)); + } else { + usersResult.remove(waitingForLoadExceptions.valueAt(a)); + } + } + } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putUsers(users, true); + MessagesController.getInstance(currentAccount).putChats(chats, true); + MessagesController.getInstance(currentAccount).putEncryptedChats(encryptedChats, true); + exceptionUsers = usersResult; + exceptionChats = chatsResult; + adapter.notifyItemChanged(messageExceptionsRow); + adapter.notifyItemChanged(groupExceptionsRow); + }); + }); + + messageSectionRow = rowCount++; messageAlertRow = rowCount++; messagePreviewRow = rowCount++; @@ -116,6 +254,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif } else { messagePriorityRow = -1; } + messageExceptionsRow = rowCount++; groupSectionRow2 = rowCount++; groupSectionRow = rowCount++; groupAlertRow = rowCount++; @@ -129,6 +268,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif } else { groupPriorityRow = -1; } + groupExceptionsRow = rowCount++; inappSectionRow2 = rowCount++; inappSectionRow = rowCount++; inappSoundRow = rowCount++; @@ -200,286 +340,253 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif listView.setVerticalScrollBarEnabled(false); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setAdapter(adapter = new ListAdapter(context)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, final int position) { - boolean enabled = false; + listView.setOnItemClickListener((view, position) -> { + boolean enabled = false; + if (getParentActivity() == null) { + return; + } + if (position == messageAlertRow || position == groupAlertRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + if (position == messageAlertRow) { + enabled = preferences.getBoolean("EnableAll", true); + editor.putBoolean("EnableAll", !enabled); + } else if (position == groupAlertRow) { + enabled = preferences.getBoolean("EnableGroup", true); + editor.putBoolean("EnableGroup", !enabled); + } + editor.commit(); + updateServerNotificationsSettings(position == groupAlertRow); + } else if (position == messagePreviewRow || position == groupPreviewRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + if (position == messagePreviewRow) { + enabled = preferences.getBoolean("EnablePreviewAll", true); + editor.putBoolean("EnablePreviewAll", !enabled); + } else if (position == groupPreviewRow) { + enabled = preferences.getBoolean("EnablePreviewGroup", true); + editor.putBoolean("EnablePreviewGroup", !enabled); + } + editor.commit(); + updateServerNotificationsSettings(position == groupPreviewRow); + } else if (position == messageSoundRow || position == groupSoundRow || position == callsRingtoneRow) { + try { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); + tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, position == callsRingtoneRow ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION); + tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); + tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(position == callsRingtoneRow ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION)); + Uri currentSound = null; + + String defaultPath = null; + Uri defaultUri = position == callsRingtoneRow ? Settings.System.DEFAULT_RINGTONE_URI : Settings.System.DEFAULT_NOTIFICATION_URI; + if (defaultUri != null) { + defaultPath = defaultUri.getPath(); + } + + if (position == messageSoundRow) { + String path = preferences.getString("GlobalSoundPath", defaultPath); + if (path != null && !path.equals("NoSound")) { + if (path.equals(defaultPath)) { + currentSound = defaultUri; + } else { + currentSound = Uri.parse(path); + } + } + } else if (position == groupSoundRow) { + String path = preferences.getString("GroupSoundPath", defaultPath); + if (path != null && !path.equals("NoSound")) { + if (path.equals(defaultPath)) { + currentSound = defaultUri; + } else { + currentSound = Uri.parse(path); + } + } + } else if (position == callsRingtoneRow) { + String path = preferences.getString("CallsRingtonfePath", defaultPath); + if (path != null && !path.equals("NoSound")) { + if (path.equals(defaultPath)) { + currentSound = defaultUri; + } else { + currentSound = Uri.parse(path); + } + } + } + tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); + startActivityForResult(tmpIntent, position); + } catch (Exception e) { + FileLog.e(e); + } + } else if (position == resetNotificationsRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("ResetNotificationsAlert", R.string.ResetNotificationsAlert)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("Reset", R.string.Reset), (dialogInterface, i) -> { + if (reseting) { + return; + } + reseting = true; + TLRPC.TL_account_resetNotifySettings req = new TLRPC.TL_account_resetNotifySettings(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).enableJoined = true; + reseting = false; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.commit(); + exceptionChats.clear(); + exceptionUsers.clear(); + adapter.notifyDataSetChanged(); + if (getParentActivity() != null) { + Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("ResetNotificationsText", R.string.ResetNotificationsText), Toast.LENGTH_SHORT); + toast.show(); + } + })); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (position == inappSoundRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableInAppSounds", true); + editor.putBoolean("EnableInAppSounds", !enabled); + editor.commit(); + } else if (position == inappVibrateRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableInAppVibrate", true); + editor.putBoolean("EnableInAppVibrate", !enabled); + editor.commit(); + } else if (position == inappPreviewRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableInAppPreview", true); + editor.putBoolean("EnableInAppPreview", !enabled); + editor.commit(); + } else if (position == inchatSoundRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableInChatSound", true); + editor.putBoolean("EnableInChatSound", !enabled); + editor.commit(); + NotificationsController.getInstance(currentAccount).setInChatSoundEnabled(!enabled); + } else if (position == inappPriorityRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableInAppPriority", false); + editor.putBoolean("EnableInAppPriority", !enabled); + editor.commit(); + } else if (position == contactJoinedRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableContactJoined", true); + MessagesController.getInstance(currentAccount).enableJoined = !enabled; + editor.putBoolean("EnableContactJoined", !enabled); + editor.commit(); + } else if (position == pinnedMessageRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("PinnedMessages", true); + editor.putBoolean("PinnedMessages", !enabled); + editor.commit(); + } else if (position == androidAutoAlertRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("EnableAutoNotifications", false); + editor.putBoolean("EnableAutoNotifications", !enabled); + editor.commit(); + } else if (position == badgeNumberRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + SharedPreferences.Editor editor = preferences.edit(); + enabled = NotificationsController.getInstance(currentAccount).showBadgeNumber; + NotificationsController.getInstance(currentAccount).showBadgeNumber = !enabled; + editor.putBoolean("badgeNumber", NotificationsController.getInstance(currentAccount).showBadgeNumber); + editor.commit(); + NotificationsController.getInstance(currentAccount).setBadgeEnabled(!enabled); + } else if (position == notificationsServiceConnectionRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + enabled = preferences.getBoolean("pushConnection", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("pushConnection", !enabled); + editor.commit(); + if (!enabled) { + ConnectionsManager.getInstance(currentAccount).setPushConnectionEnabled(true); + } else { + ConnectionsManager.getInstance(currentAccount).setPushConnectionEnabled(false); + } + } else if (position == notificationsServiceRow) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + enabled = preferences.getBoolean("pushService", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("pushService", !enabled); + editor.commit(); + if (!enabled) { + ApplicationLoader.startPushService(); + } else { + ApplicationLoader.stopPushService(); + } + } else if (position == messageLedRow || position == groupLedRow) { if (getParentActivity() == null) { return; } - if (position == messageAlertRow || position == groupAlertRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (position == messageAlertRow) { - enabled = preferences.getBoolean("EnableAll", true); - editor.putBoolean("EnableAll", !enabled); - } else if (position == groupAlertRow) { - enabled = preferences.getBoolean("EnableGroup", true); - editor.putBoolean("EnableGroup", !enabled); - } - editor.commit(); - updateServerNotificationsSettings(position == groupAlertRow); - } else if (position == messagePreviewRow || position == groupPreviewRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (position == messagePreviewRow) { - enabled = preferences.getBoolean("EnablePreviewAll", true); - editor.putBoolean("EnablePreviewAll", !enabled); - } else if (position == groupPreviewRow) { - enabled = preferences.getBoolean("EnablePreviewGroup", true); - editor.putBoolean("EnablePreviewGroup", !enabled); - } - editor.commit(); - updateServerNotificationsSettings(position == groupPreviewRow); - } else if (position == messageSoundRow || position == groupSoundRow || position == callsRingtoneRow) { - try { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, position == callsRingtoneRow ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(position == callsRingtoneRow ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION)); - Uri currentSound = null; - - String defaultPath = null; - Uri defaultUri = position == callsRingtoneRow ? Settings.System.DEFAULT_RINGTONE_URI : Settings.System.DEFAULT_NOTIFICATION_URI; - if (defaultUri != null) { - defaultPath = defaultUri.getPath(); - } - - if (position == messageSoundRow) { - String path = preferences.getString("GlobalSoundPath", defaultPath); - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - } else if (position == groupSoundRow) { - String path = preferences.getString("GroupSoundPath", defaultPath); - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - } else if (position == callsRingtoneRow) { - String path = preferences.getString("CallsRingtonfePath", defaultPath); - if (path != null && !path.equals("NoSound")) { - if (path.equals(defaultPath)) { - currentSound = defaultUri; - } else { - currentSound = Uri.parse(path); - } - } - } - tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound); - startActivityForResult(tmpIntent, position); - } catch (Exception e) { - FileLog.e(e); - } - } else if (position == resetNotificationsRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("ResetNotificationsAlert", R.string.ResetNotificationsAlert)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("Reset", R.string.Reset), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (reseting) { - return; - } - reseting = true; - TLRPC.TL_account_resetNotifySettings req = new TLRPC.TL_account_resetNotifySettings(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance(currentAccount).enableJoined = true; - reseting = false; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - editor.clear(); - editor.commit(); - adapter.notifyDataSetChanged(); - if (getParentActivity() != null) { - Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("ResetNotificationsText", R.string.ResetNotificationsText), Toast.LENGTH_SHORT); - toast.show(); - } - } - }); - } - }); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else if (position == inappSoundRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableInAppSounds", true); - editor.putBoolean("EnableInAppSounds", !enabled); - editor.commit(); - } else if (position == inappVibrateRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableInAppVibrate", true); - editor.putBoolean("EnableInAppVibrate", !enabled); - editor.commit(); - } else if (position == inappPreviewRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableInAppPreview", true); - editor.putBoolean("EnableInAppPreview", !enabled); - editor.commit(); - } else if (position == inchatSoundRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableInChatSound", true); - editor.putBoolean("EnableInChatSound", !enabled); - editor.commit(); - NotificationsController.getInstance(currentAccount).setInChatSoundEnabled(!enabled); - } else if (position == inappPriorityRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableInAppPriority", false); - editor.putBoolean("EnableInAppPriority", !enabled); - editor.commit(); - } else if (position == contactJoinedRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableContactJoined", true); - MessagesController.getInstance(currentAccount).enableJoined = !enabled; - editor.putBoolean("EnableContactJoined", !enabled); - editor.commit(); - } else if (position == pinnedMessageRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("PinnedMessages", true); - editor.putBoolean("PinnedMessages", !enabled); - editor.commit(); - } else if (position == androidAutoAlertRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = preferences.getBoolean("EnableAutoNotifications", false); - editor.putBoolean("EnableAutoNotifications", !enabled); - editor.commit(); - } else if (position == badgeNumberRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - enabled = NotificationsController.getInstance(currentAccount).showBadgeNumber; - NotificationsController.getInstance(currentAccount).showBadgeNumber = !enabled; - editor.putBoolean("badgeNumber", NotificationsController.getInstance(currentAccount).showBadgeNumber); - editor.commit(); - NotificationsController.getInstance(currentAccount).setBadgeEnabled(!enabled); - } else if (position == notificationsServiceConnectionRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - enabled = preferences.getBoolean("pushConnection", true); - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean("pushConnection", !enabled); - editor.commit(); - if (!enabled) { - ConnectionsManager.getInstance(currentAccount).setPushConnectionEnabled(true); - } else { - ConnectionsManager.getInstance(currentAccount).setPushConnectionEnabled(false); - } - } else if (position == notificationsServiceRow) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - enabled = preferences.getBoolean("pushService", true); - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean("pushService", !enabled); - editor.commit(); - if (!enabled) { - ApplicationLoader.startPushService(); - } else { - ApplicationLoader.stopPushService(); - } - } else if (position == messageLedRow || position == groupLedRow) { - if (getParentActivity() == null) { - return; - } - showDialog(AlertsCreator.createColorSelectDialog(getParentActivity(), 0, position == groupLedRow, position == messageLedRow, new Runnable() { - @Override - public void run() { - adapter.notifyItemChanged(position); - } - })); - } else if (position == messagePopupNotificationRow || position == groupPopupNotificationRow) { - if (getParentActivity() == null) { - return; - } - showDialog(AlertsCreator.createPopupSelectDialog(getParentActivity(), NotificationsSettingsActivity.this, position == groupPopupNotificationRow, position == messagePopupNotificationRow, new Runnable() { - @Override - public void run() { - adapter.notifyItemChanged(position); - } - })); - } else if (position == messageVibrateRow || position == groupVibrateRow || position == callsVibrateRow) { - if (getParentActivity() == null) { - return; - } - String key = null; - if (position == messageVibrateRow) { - key = "vibrate_messages"; - } else if (position == groupVibrateRow) { - key = "vibrate_group"; - } else if (position == callsVibrateRow) { - key = "vibrate_calls"; - } - showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), NotificationsSettingsActivity.this, 0, key, new Runnable() { - @Override - public void run() { - adapter.notifyItemChanged(position); - } - })); - } else if (position == messagePriorityRow || position == groupPriorityRow) { - showDialog(AlertsCreator.createPrioritySelectDialog(getParentActivity(), NotificationsSettingsActivity.this, 0, position == groupPriorityRow, position == messagePriorityRow, new Runnable() { - @Override - public void run() { - adapter.notifyItemChanged(position); - } - })); - } else if (position == repeatRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("RepeatNotifications", R.string.RepeatNotifications)); - builder.setItems(new CharSequence[]{ - LocaleController.getString("RepeatDisabled", R.string.RepeatDisabled), - LocaleController.formatPluralString("Minutes", 5), - LocaleController.formatPluralString("Minutes", 10), - LocaleController.formatPluralString("Minutes", 30), - LocaleController.formatPluralString("Hours", 1), - LocaleController.formatPluralString("Hours", 2), - LocaleController.formatPluralString("Hours", 4) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int minutes = 0; - if (which == 1) { - minutes = 5; - } else if (which == 2) { - minutes = 10; - } else if (which == 3) { - minutes = 30; - } else if (which == 4) { - minutes = 60; - } else if (which == 5) { - minutes = 60 * 2; - } else if (which == 6) { - minutes = 60 * 4; - } - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("repeat_messages", minutes).commit(); - adapter.notifyItemChanged(position); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + showDialog(AlertsCreator.createColorSelectDialog(getParentActivity(), 0, position == groupLedRow, position == messageLedRow, () -> adapter.notifyItemChanged(position))); + } else if (position == messagePopupNotificationRow || position == groupPopupNotificationRow) { + if (getParentActivity() == null) { + return; } - if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(!enabled); + showDialog(AlertsCreator.createPopupSelectDialog(getParentActivity(), NotificationsSettingsActivity.this, position == groupPopupNotificationRow, position == messagePopupNotificationRow, () -> adapter.notifyItemChanged(position))); + } else if (position == messageVibrateRow || position == groupVibrateRow || position == callsVibrateRow) { + if (getParentActivity() == null) { + return; } + String key = null; + if (position == messageVibrateRow) { + key = "vibrate_messages"; + } else if (position == groupVibrateRow) { + key = "vibrate_group"; + } else if (position == callsVibrateRow) { + key = "vibrate_calls"; + } + showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), NotificationsSettingsActivity.this, 0, key, () -> adapter.notifyItemChanged(position))); + } else if (position == messagePriorityRow || position == groupPriorityRow) { + showDialog(AlertsCreator.createPrioritySelectDialog(getParentActivity(), NotificationsSettingsActivity.this, 0, position == groupPriorityRow, position == messagePriorityRow, () -> adapter.notifyItemChanged(position))); + } else if (position == messageExceptionsRow || position == groupExceptionsRow) { + presentFragment(new NotificationsExceptionsActivity(position == messageExceptionsRow ? exceptionUsers : exceptionChats)); + } else if (position == repeatRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("RepeatNotifications", R.string.RepeatNotifications)); + builder.setItems(new CharSequence[]{ + LocaleController.getString("RepeatDisabled", R.string.RepeatDisabled), + LocaleController.formatPluralString("Minutes", 5), + LocaleController.formatPluralString("Minutes", 10), + LocaleController.formatPluralString("Minutes", 30), + LocaleController.formatPluralString("Hours", 1), + LocaleController.formatPluralString("Hours", 2), + LocaleController.formatPluralString("Hours", 4) + }, (dialog, which) -> { + int minutes = 0; + if (which == 1) { + minutes = 5; + } else if (which == 2) { + minutes = 10; + } else if (which == 3) { + minutes = 30; + } else if (which == 4) { + minutes = 60; + } else if (which == 5) { + minutes = 60 * 2; + } else if (which == 6) { + minutes = 60 * 4; + } + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().putInt("repeat_messages", minutes).commit(); + adapter.notifyItemChanged(position); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!enabled); } }); @@ -500,11 +607,8 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif req.settings.mute_until = preferences.getBoolean("EnableGroup", true) ? 0 : Integer.MAX_VALUE; req.settings.show_previews = preferences.getBoolean("EnablePreviewGroup", true); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } @@ -569,6 +673,14 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif } } + @Override + public void onResume() { + super.onResume(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.notificationsSettingsUpdated) { @@ -694,7 +806,67 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif case 2: { TextDetailSettingsCell settingsCell = (TextDetailSettingsCell) holder.itemView; settingsCell.setMultilineDetail(true); - settingsCell.setTextAndValue(LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications), LocaleController.getString("UndoAllCustom", R.string.UndoAllCustom), false); + if (position == resetNotificationsRow) { + settingsCell.setTextAndValue(LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications), LocaleController.getString("UndoAllCustom", R.string.UndoAllCustom), false); + } else if (position == messageExceptionsRow || position == groupExceptionsRow) { + ArrayList arrayList; + if (position == groupExceptionsRow) { + arrayList = exceptionChats; + } else { + arrayList = exceptionUsers; + } + StringBuilder builder = new StringBuilder(); + int length = 0; + for (int a = 0, size = arrayList.size(); a < size; a++) { + NotificationException exception = arrayList.get(a); + int lower_id = (int) exception.did; + int high_id = (int) (exception.did >> 32); + + String name = null; + if (lower_id != 0) { + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); + if (user != null) { + name = ContactsController.formatName(user.first_name, user.last_name); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); + if (chat != null) { + name = chat.title; + } + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance(currentAccount).getEncryptedChat(high_id); + if (encryptedChat != null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(encryptedChat.user_id); + if (user != null) { + name = ContactsController.formatName(user.first_name, user.last_name); + } + } + } + if (name != null) { + if (name.length() > 20) { + int pos = 19; + while (pos >= 0 && name.charAt(pos) == ' ') { + pos--; + } + name = name.substring(0, pos + 1) + ".."; + } + length += settingsCell.getValueTextView().getPaint().measureText(name); + if (builder.length() > 0) { + builder.append(", "); + } + builder.append(name); + if (length > AndroidUtilities.displaySize.x * 2.0f) { + if (a != size - 1) { + builder.append(", ..."); + } + break; + } + } + } + settingsCell.setTextAndValue(LocaleController.getString("NotificationsExceptions", R.string.NotificationsExceptions), builder.toString(), false); + } break; } case 3: { @@ -774,14 +946,32 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif value = preferences.getInt("priority_group", 1); } if (value == 0) { - textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityHigh", R.string.NotificationsPriorityHigh), false); + textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityHigh", R.string.NotificationsPriorityHigh), true); } else if (value == 1 || value == 2) { - textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityUrgent", R.string.NotificationsPriorityUrgent), false); + textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityUrgent", R.string.NotificationsPriorityUrgent), true); } else if (value == 4) { - textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityLow", R.string.NotificationsPriorityLow), false); + textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityLow", R.string.NotificationsPriorityLow), true); } else if (value == 5) { - textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityMedium", R.string.NotificationsPriorityMedium), false); + textCell.setTextAndValue(LocaleController.getString("NotificationsImportance", R.string.NotificationsImportance), LocaleController.getString("NotificationsPriorityMedium", R.string.NotificationsPriorityMedium), true); } + } else if (position == messageExceptionsRow || position == groupExceptionsRow) { + String text; + if (position == messageExceptionsRow && exceptionUsers == null || position == groupExceptionsRow && exceptionChats == null) { + text = LocaleController.getString("Loading", R.string.Loading); + } else if (position == messageExceptionsRow) { + if (exceptionUsers.isEmpty()) { + text = LocaleController.getString("EmptyExceptions", R.string.EmptyExceptions); + } else { + text = String.format("%d", exceptionUsers.size()); + } + } else { + if (exceptionChats.isEmpty()) { + text = LocaleController.getString("EmptyExceptions", R.string.EmptyExceptions); + } else { + text = String.format("%d", exceptionChats.size()); + } + } + textCell.setTextAndValue(LocaleController.getString("NotificationsExceptions", R.string.NotificationsExceptions), text, false); } else if (position == messagePopupNotificationRow || position == groupPopupNotificationRow) { int option = 0; if (position == messagePopupNotificationRow) { @@ -823,7 +1013,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif position == inappSectionRow2 || position == otherSectionRow2 || position == resetSectionRow2 || position == callsSectionRow2) { return 4; - } else if (position == resetNotificationsRow) { + } else if (position == resetNotificationsRow || position == messageExceptionsRow && exceptionUsers != null && !exceptionUsers.isEmpty() || position == groupExceptionsRow && exceptionChats != null && !exceptionChats.isEmpty()) { return 2; } else { return 5; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index 9bbee3124..0a2ecec41 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -6,11 +6,9 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.Activity; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -47,7 +45,6 @@ import android.util.Base64; import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; -import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; @@ -78,6 +75,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MrzRecognizer; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SRPHelper; import org.telegram.messenger.SecureDocument; import org.telegram.messenger.SecureDocumentKey; import org.telegram.messenger.SendMessagesHelper; @@ -129,6 +127,7 @@ import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; @@ -148,15 +147,21 @@ public class PassportActivity extends BaseFragment implements NotificationCenter public final static int TYPE_MANAGE = 8; private final static int FIELD_NAME = 0; - private final static int FIELD_SURNAME = 1; - private final static int FIELD_BIRTHDAY = 2; - private final static int FIELD_GENDER = 3; - private final static int FIELD_CITIZENSHIP = 4; - private final static int FIELD_RESIDENCE = 5; - private final static int FIELD_CARDNUMBER = 6; - private final static int FIELD_EXPIRE = 7; - private final static int FIELD_IDENTITY_COUNT = 8; - private final static int FIELD_IDENTITY_NODOC_COUNT = 6; + private final static int FIELD_MIDNAME = 1; + private final static int FIELD_SURNAME = 2; + private final static int FIELD_BIRTHDAY = 3; + private final static int FIELD_GENDER = 4; + private final static int FIELD_CITIZENSHIP = 5; + private final static int FIELD_RESIDENCE = 6; + private final static int FIELD_CARDNUMBER = 7; + private final static int FIELD_EXPIRE = 8; + private final static int FIELD_IDENTITY_COUNT = 9; + private final static int FIELD_IDENTITY_NODOC_COUNT = 7; + + private final static int FIELD_NATIVE_NAME = 0; + private final static int FIELD_NATIVE_MIDNAME = 1; + private final static int FIELD_NATIVE_SURNAME = 2; + private final static int FIELD_NATIVE_COUNT = 3; private final static int FIELD_STREET1 = 0; private final static int FIELD_STREET2 = 1; @@ -178,6 +183,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter private final static int UPLOADING_TYPE_SELFIE = 1; private final static int UPLOADING_TYPE_FRONT = 2; private final static int UPLOADING_TYPE_REVERSE = 3; + private final static int UPLOADING_TYPE_TRANSLATION = 4; private String initialValues; private int currentActivityType; @@ -193,12 +199,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter private int[] currentExpireDate = new int[3]; private TLRPC.TL_account_authorizationForm currentForm; - private TLRPC.SecureValueType currentType; - private TLRPC.SecureValueType currentDocumentsType; - private ArrayList availableDocumentTypes; + private TLRPC.TL_secureRequiredType currentType; + private TLRPC.TL_secureRequiredType currentDocumentsType; + private ArrayList availableDocumentTypes; private TLRPC.TL_secureValue currentTypeValue; private TLRPC.TL_secureValue currentDocumentsTypeValue; - private TLRPC.account_Password currentPassword; + private TLRPC.TL_account_password currentPassword; private TLRPC.TL_auth_sentCode currentPhoneVerification; private ActionBarMenuItem doneItem; @@ -211,24 +217,37 @@ public class PassportActivity extends BaseFragment implements NotificationCenter private TextSettingsCell uploadDocumentCell; private View extraBackgroundView; + private View extraBackgroundView2; private TextDetailSettingsCell uploadFrontCell; private TextDetailSettingsCell uploadReverseCell; private TextDetailSettingsCell uploadSelfieCell; + private TextSettingsCell uploadTranslationCell; private EditTextBoldCursor[] inputFields; private ViewGroup[] inputFieldContainers; + private EditTextBoldCursor[] inputExtraFields; private ScrollView scrollView; private LinearLayout linearLayout2; private LinearLayout documentsLayout; private LinearLayout frontLayout; private LinearLayout reverseLayout; private LinearLayout selfieLayout; + private LinearLayout translationLayout; private LinearLayout currentPhotoViewerLayout; private HeaderCell headerCell; private ArrayList dividers = new ArrayList<>(); private ShadowSectionCell sectionCell; + private ShadowSectionCell sectionCell2; private TextInfoPrivacyCell bottomCell; + private TextInfoPrivacyCell bottomCellTranslation; + private TextInfoPrivacyCell topErrorCell; + private TextInfoPrivacyCell nativeInfoCell; private TextSettingsCell scanDocumentCell; + private boolean[] nonLatinNames = new boolean[3]; + private boolean allowNonLatinName = true; + + private boolean documentOnly; + private TextView plusTextView; private TextSettingsCell addDocumentCell; @@ -285,26 +304,31 @@ public class PassportActivity extends BaseFragment implements NotificationCenter private ArrayList documents = new ArrayList<>(); private SecureDocument selfieDocument; + private ArrayList translationDocuments = new ArrayList<>(); private SecureDocument frontDocument; private SecureDocument reverseDocument; private HashMap documentsCells = new HashMap<>(); private HashMap uploadingDocuments = new HashMap<>(); - private HashMap> typesValues = new HashMap<>(); - private HashMap typesViews = new HashMap<>(); + private HashMap> typesValues = new HashMap<>(); + private HashMap typesViews = new HashMap<>(); + private HashMap documentsToTypesLink = new HashMap<>(); private HashMap currentValues; + private HashMap currentDocumentValues; private HashMap> errorsMap = new HashMap<>(); + private HashMap mainErrorsMap = new HashMap<>(); private HashMap fieldsErrors; private HashMap documentsErrors; private HashMap errorsValues = new HashMap<>(); private CharSequence noAllDocumentsErrorText; + private CharSequence noAllTranslationErrorText; private PassportActivityDelegate delegate; private boolean needActivityResult; private interface PassportActivityDelegate { - void saveValue(TLRPC.SecureValueType type, String text, String json, TLRPC.SecureValueType documentsType, String documentsJson, ArrayList documents, SecureDocument selfie, SecureDocument front, SecureDocument reverse, Runnable finishRunnable, ErrorRunnable errorRunnable); - void deleteValue(TLRPC.SecureValueType type, TLRPC.SecureValueType documentsType, boolean deleteType, Runnable finishRunnable, ErrorRunnable errorRunnable); + void saveValue(TLRPC.TL_secureRequiredType type, String text, String json, TLRPC.TL_secureRequiredType documentType, String documentsJson, ArrayList documents, SecureDocument selfie, ArrayList translationDocuments, SecureDocument front, SecureDocument reverse, Runnable finishRunnable, ErrorRunnable errorRunnable); + void deleteValue(TLRPC.TL_secureRequiredType type, TLRPC.TL_secureRequiredType documentType, ArrayList documentRequiredTypes, boolean deleteType, Runnable finishRunnable, ErrorRunnable errorRunnable); SecureDocument saveFile(TLRPC.TL_secureFile secureFile); } @@ -336,6 +360,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter SecureDocument document; if (uploadingFileType == UPLOADING_TYPE_SELFIE) { document = selfieDocument; + } else if (uploadingFileType == UPLOADING_TYPE_TRANSLATION) { + document = translationDocuments.get(index); } else if (uploadingFileType == UPLOADING_TYPE_FRONT) { document = frontDocument; } else if (uploadingFileType == UPLOADING_TYPE_REVERSE) { @@ -352,6 +378,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (uploadingFileType == UPLOADING_TYPE_SELFIE) { selfieDocument = null; key = "selfie" + hash; + } else if (uploadingFileType == UPLOADING_TYPE_TRANSLATION) { + key = "translation" + hash; } else if (uploadingFileType == UPLOADING_TYPE_FRONT) { frontDocument = null; key = "front" + hash; @@ -631,8 +659,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - public PassportActivity(int type, int botId, String scope, String publicKey, String payload, String callbackUrl, TLRPC.TL_account_authorizationForm form, TLRPC.account_Password accountPassword) { - this(type, form, accountPassword, null, null, null, null, null); + public PassportActivity(int type, int botId, String scope, String publicKey, String payload, String callbackUrl, TLRPC.TL_account_authorizationForm form, TLRPC.TL_account_password accountPassword) { + this(type, form, accountPassword, null, null, null, null, null, null); currentBotId = botId; currentPayload = payload; currentScope = scope; @@ -641,6 +669,44 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (type == TYPE_REQUEST) { if (!form.errors.isEmpty()) { try { + Collections.sort(form.errors, new Comparator() { + + int getErrorValue(TLRPC.SecureValueError error) { + if (error instanceof TLRPC.TL_secureValueError) { + return 0; + } else if (error instanceof TLRPC.TL_secureValueErrorFrontSide) { + return 1; + } else if (error instanceof TLRPC.TL_secureValueErrorReverseSide) { + return 2; + } else if (error instanceof TLRPC.TL_secureValueErrorSelfie) { + return 3; + } else if (error instanceof TLRPC.TL_secureValueErrorTranslationFile) { + return 4; + } else if (error instanceof TLRPC.TL_secureValueErrorTranslationFiles) { + return 5; + } else if (error instanceof TLRPC.TL_secureValueErrorFile) { + return 6; + } else if (error instanceof TLRPC.TL_secureValueErrorFiles) { + return 7; + } else if (error instanceof TLRPC.TL_secureValueErrorData) { + TLRPC.TL_secureValueErrorData errorData = (TLRPC.TL_secureValueErrorData) error; + return getFieldCost(errorData.field); + } + return 100; + } + + @Override + public int compare(TLRPC.SecureValueError e1, TLRPC.SecureValueError e2) { + int val1 = getErrorValue(e1); + int val2 = getErrorValue(e2); + if (val1 < val2) { + return -1; + } else if (val1 > val2) { + return 1; + } + return 0; + } + }); for (int a = 0, size = form.errors.size(); a < size; a++) { TLRPC.SecureValueError secureValueError = form.errors.get(a); String key; @@ -668,6 +734,17 @@ public class PassportActivity extends BaseFragment implements NotificationCenter description = secureValueErrorSelfie.text; file_hash = secureValueErrorSelfie.file_hash; target = "selfie"; + } else if (secureValueError instanceof TLRPC.TL_secureValueErrorTranslationFile) { + TLRPC.TL_secureValueErrorTranslationFile secureValueErrorTranslationFile = (TLRPC.TL_secureValueErrorTranslationFile) secureValueError; + key = getNameForType(secureValueErrorTranslationFile.type); + description = secureValueErrorTranslationFile.text; + file_hash = secureValueErrorTranslationFile.file_hash; + target = "translation"; + } else if (secureValueError instanceof TLRPC.TL_secureValueErrorTranslationFiles) { + TLRPC.TL_secureValueErrorTranslationFiles secureValueErrorTranslationFiles = (TLRPC.TL_secureValueErrorTranslationFiles) secureValueError; + key = getNameForType(secureValueErrorTranslationFiles.type); + description = secureValueErrorTranslationFiles.text; + target = "translation"; } else if (secureValueError instanceof TLRPC.TL_secureValueErrorFile) { TLRPC.TL_secureValueErrorFile secureValueErrorFile = (TLRPC.TL_secureValueErrorFile) secureValueError; key = getNameForType(secureValueErrorFile.type); @@ -679,6 +756,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter key = getNameForType(secureValueErrorFiles.type); description = secureValueErrorFiles.text; target = "files"; + } else if (secureValueError instanceof TLRPC.TL_secureValueError) { + TLRPC.TL_secureValueError secureValueErrorAll = (TLRPC.TL_secureValueError) secureValueError; + key = getNameForType(secureValueErrorAll.type); + description = secureValueErrorAll.text; + file_hash = secureValueErrorAll.hash; + target = "error_all"; } else if (secureValueError instanceof TLRPC.TL_secureValueErrorData) { TLRPC.TL_secureValueErrorData secureValueErrorData = (TLRPC.TL_secureValueErrorData) secureValueError; boolean found = false; @@ -704,6 +787,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (vals == null) { vals = new HashMap<>(); errorsMap.put(key, vals); + mainErrorsMap.put(key, description); } String hash; if (file_hash != null) { @@ -723,10 +807,18 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } else if ("selfie".equals(target)) { vals.put("selfie" + hash, description); + } else if ("translation".equals(target)) { + if (file_hash != null) { + vals.put("translation" + hash, description); + } else { + vals.put("translation_all", description); + } } else if ("front".equals(target)) { vals.put("front" + hash, description); } else if ("reverse".equals(target)) { vals.put("reverse" + hash, description); + } else if ("error_all".equals(target)) { + vals.put("error_all", description); } } } catch (Exception ignore) { @@ -736,16 +828,20 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - public PassportActivity(int type, TLRPC.TL_account_authorizationForm form, TLRPC.account_Password accountPassword, TLRPC.SecureValueType secureType, TLRPC.TL_secureValue secureValue, TLRPC.SecureValueType secureDocumentsType, TLRPC.TL_secureValue secureDocumentsValue, HashMap values) { + public PassportActivity(int type, TLRPC.TL_account_authorizationForm form, TLRPC.TL_account_password accountPassword, TLRPC.TL_secureRequiredType secureType, TLRPC.TL_secureValue secureValue, TLRPC.TL_secureRequiredType secureDocumentsType, TLRPC.TL_secureValue secureDocumentsValue, HashMap values, HashMap documentValues) { super(); currentActivityType = type; currentForm = form; currentType = secureType; + if (currentType != null) { + allowNonLatinName = currentType.native_names; + } currentTypeValue = secureValue; currentDocumentsType = secureDocumentsType; currentDocumentsTypeValue = secureDocumentsValue; currentPassword = accountPassword; currentValues = values; + currentDocumentValues = documentValues; if (currentActivityType == TYPE_PHONE) { permissionsItems = new ArrayList<>(); } else if (currentActivityType == TYPE_PHONE_VERIFICATION) { @@ -754,6 +850,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (currentValues == null) { currentValues = new HashMap<>(); } + if (currentDocumentValues == null) { + currentDocumentValues = new HashMap<>(); + } if (type == TYPE_PASSWORD) { if (UserConfig.getInstance(currentAccount).savedPasswordHash != null && UserConfig.getInstance(currentAccount).savedSaltedPassword != null) { usingSavedPassword = 1; @@ -763,13 +862,22 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (currentPassword == null) { loadPasswordInfo(); } else { - byte[] salt = new byte[currentPassword.new_salt.length + 8]; - Utilities.random.nextBytes(salt); - System.arraycopy(currentPassword.new_salt, 0, salt, 0, currentPassword.new_salt.length); - currentPassword.new_salt = salt; + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + if (usingSavedPassword == 1) { + onPasswordDone(true); + } } - if (usingSavedPassword == 1) { - onPasswordDone(true); + if (!SharedConfig.isPassportConfigLoaded()) { + TLRPC.TL_help_getPassportConfig req = new TLRPC.TL_help_getPassportConfig(); + req.hash = SharedConfig.passportConfigHash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_help_passportConfig) { + TLRPC.TL_help_passportConfig res = (TLRPC.TL_help_passportConfig) response; + SharedConfig.setPassportConfig(res.countries_langs.data, res.hash); + } else { + SharedConfig.getCountryLangs(); + } + })); } } } @@ -783,13 +891,10 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (currentActivityType == TYPE_PASSWORD && inputFieldContainers != null && inputFieldContainers[FIELD_PASSWORD] != null && inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { inputFields[FIELD_PASSWORD].requestFocus(); AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (inputFieldContainers != null && inputFieldContainers[FIELD_PASSWORD] != null && inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { - inputFields[FIELD_PASSWORD].requestFocus(); - AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); - } + AndroidUtilities.runOnUIThread(() -> { + if (inputFieldContainers != null && inputFieldContainers[FIELD_PASSWORD] != null && inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { + inputFields[FIELD_PASSWORD].requestFocus(); + AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); } }, 200); } @@ -840,7 +945,6 @@ public class PassportActivity extends BaseFragment implements NotificationCenter progressDialog = null; } } - //AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); TODO check } @Override @@ -850,6 +954,132 @@ public class PassportActivity extends BaseFragment implements NotificationCenter actionBar.setAllowOverlayTitle(true); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + + private boolean onIdentityDone(Runnable finishRunnable, ErrorRunnable errorRunnable) { + if (!uploadingDocuments.isEmpty() || checkFieldsForError()) { + return false; + } + if (allowNonLatinName) { + allowNonLatinName = false; + boolean error = false; + for (int a = 0; a < nonLatinNames.length; a++) { + if (nonLatinNames[a]) { + inputFields[a].setErrorText(LocaleController.getString("PassportUseLatinOnly", R.string.PassportUseLatinOnly)); + if (!error) { + error = true; + String firstName = nonLatinNames[0] ? getTranslitString(inputExtraFields[FIELD_NATIVE_NAME].getText().toString()) : inputFields[FIELD_NAME].getText().toString(); + String middleName = nonLatinNames[1] ? getTranslitString(inputExtraFields[FIELD_NATIVE_MIDNAME].getText().toString()) : inputFields[FIELD_MIDNAME].getText().toString(); + String lastName = nonLatinNames[2] ? getTranslitString(inputExtraFields[FIELD_NATIVE_SURNAME].getText().toString()) : inputFields[FIELD_SURNAME].getText().toString(); + + if (!TextUtils.isEmpty(firstName) && !TextUtils.isEmpty(middleName) && !TextUtils.isEmpty(lastName)) { + int num = a; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("PassportNameCheckAlert", R.string.PassportNameCheckAlert, firstName, middleName, lastName)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("Done", R.string.Done), (dialogInterface, i) -> { + inputFields[FIELD_NAME].setText(firstName); + inputFields[FIELD_MIDNAME].setText(middleName); + inputFields[FIELD_SURNAME].setText(lastName); + showEditDoneProgress(true, true); + onIdentityDone(finishRunnable, errorRunnable); + }); + builder.setNegativeButton(LocaleController.getString("Edit", R.string.Edit), (dialogInterface, i) -> onFieldError(inputFields[num])); + showDialog(builder.create()); + } else { + onFieldError(inputFields[a]); + } + } + } + } + if (error) { + return false; + } + } + if (isHasNotAnyChanges()) { + finishFragment(); + return false; + } + JSONObject json = null; + JSONObject documentsJson = null; + try { + if (!documentOnly) { + HashMap valuesToSave = new HashMap<>(currentValues); + if (currentType.native_names) { + if (nativeInfoCell.getVisibility() == View.VISIBLE) { + valuesToSave.put("first_name_native", inputExtraFields[FIELD_NATIVE_NAME].getText().toString()); + valuesToSave.put("middle_name_native", inputExtraFields[FIELD_NATIVE_MIDNAME].getText().toString()); + valuesToSave.put("last_name_native", inputExtraFields[FIELD_NATIVE_SURNAME].getText().toString()); + } else { + valuesToSave.put("first_name_native", inputFields[FIELD_NATIVE_NAME].getText().toString()); + valuesToSave.put("middle_name_native", inputFields[FIELD_NATIVE_MIDNAME].getText().toString()); + valuesToSave.put("last_name_native", inputFields[FIELD_NATIVE_SURNAME].getText().toString()); + } + } + valuesToSave.put("first_name", inputFields[FIELD_NAME].getText().toString()); + valuesToSave.put("middle_name", inputFields[FIELD_MIDNAME].getText().toString()); + valuesToSave.put("last_name", inputFields[FIELD_SURNAME].getText().toString()); + valuesToSave.put("birth_date", inputFields[FIELD_BIRTHDAY].getText().toString()); + valuesToSave.put("gender", currentGender); + valuesToSave.put("country_code", currentCitizeship); + valuesToSave.put("residence_country_code", currentResidence); + + json = new JSONObject(); + ArrayList keys = new ArrayList<>(valuesToSave.keySet()); + Collections.sort(keys, (key1, key2) -> { + int val1 = getFieldCost(key1); + int val2 = getFieldCost(key2); + if (val1 < val2) { + return -1; + } else if (val1 > val2) { + return 1; + } + return 0; + }); + for (int a = 0, size = keys.size(); a < size; a++) { + String key = keys.get(a); + json.put(key, valuesToSave.get(key)); + } + } + + if (currentDocumentsType != null) { + HashMap valuesToSave = new HashMap<>(currentDocumentValues); + valuesToSave.put("document_no", inputFields[FIELD_CARDNUMBER].getText().toString()); + if (currentExpireDate[0] != 0) { + valuesToSave.put("expiry_date", String.format(Locale.US, "%02d.%02d.%d", currentExpireDate[2], currentExpireDate[1], currentExpireDate[0])); + } else { + valuesToSave.put("expiry_date", ""); + } + + documentsJson = new JSONObject(); + ArrayList keys = new ArrayList<>(valuesToSave.keySet()); + Collections.sort(keys, (key1, key2) -> { + int val1 = getFieldCost(key1); + int val2 = getFieldCost(key2); + if (val1 < val2) { + return -1; + } else if (val1 > val2) { + return 1; + } + return 0; + }); + for (int a = 0, size = keys.size(); a < size; a++) { + String key = keys.get(a); + documentsJson.put(key, valuesToSave.get(key)); + } + } + } catch (Exception ignore) { + + } + if (fieldsErrors != null) { + fieldsErrors.clear(); + } + if (documentsErrors != null) { + documentsErrors.clear(); + } + delegate.saveValue(currentType, null, json != null ? json.toString() : null, currentDocumentsType, documentsJson != null ? documentsJson.toString() : null, null, selfieDocument, translationDocuments, frontDocument, reverseLayout != null && reverseLayout.getVisibility() == View.VISIBLE ? reverseDocument : null, finishRunnable, errorRunnable); + return true; + } + @Override public void onItemClick(int id) { if (id == -1) { @@ -899,12 +1129,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter onPasswordDone(false); return; } - final Runnable finishRunnable = new Runnable() { - @Override - public void run() { - finishFragment(); - } - }; + final Runnable finishRunnable = () -> finishFragment(); final ErrorRunnable errorRunnable = new ErrorRunnable() { @Override public void onError(String error, String text) { @@ -925,7 +1150,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } value = inputFields[FIELD_EMAIL].getText().toString(); } - delegate.saveValue(currentType, value, null, null, null, null, null, null, null, finishRunnable, errorRunnable); + delegate.saveValue(currentType, value, null, null, null, null, null, null, null, null, finishRunnable, errorRunnable); } else if (currentActivityType == TYPE_PHONE) { String value; if (useCurrentValue) { @@ -936,7 +1161,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } value = inputFields[FIELD_PHONECODE].getText().toString() + inputFields[FIELD_PHONE].getText().toString(); } - delegate.saveValue(currentType, value, null, null, null, null, null, null, null, finishRunnable, errorRunnable); + delegate.saveValue(currentType, value, null, null, null, null, null, null, null, null, finishRunnable, errorRunnable); } else if (currentActivityType == TYPE_ADDRESS) { if (!uploadingDocuments.isEmpty() || checkFieldsForError()) { return; @@ -947,50 +1172,14 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } JSONObject json = null; try { - json = new JSONObject(); - json.put("street_line1", inputFields[FIELD_STREET1].getText().toString()); - json.put("street_line2", inputFields[FIELD_STREET2].getText().toString()); - json.put("post_code", inputFields[FIELD_POSTCODE].getText().toString()); - json.put("city", inputFields[FIELD_CITY].getText().toString()); - json.put("state", inputFields[FIELD_STATE].getText().toString()); - json.put("country_code", currentCitizeship); - } catch (Exception ignore) { - - } - if (fieldsErrors != null) { - fieldsErrors.clear(); - } - if (documentsErrors != null) { - documentsErrors.clear(); - } - delegate.saveValue(currentType, null, json.toString(), currentDocumentsType, null, documents, selfieDocument, null, null, finishRunnable, errorRunnable); - } else if (currentActivityType == TYPE_IDENTITY) { - if (!uploadingDocuments.isEmpty() || checkFieldsForError()) { - return; - } - if (isHasNotAnyChanges()) { - finishFragment(); - return; - } - JSONObject json = null; - JSONObject documentsJson = null; - try { - json = new JSONObject(); - json.put("first_name", inputFields[FIELD_NAME].getText().toString()); - json.put("last_name", inputFields[FIELD_SURNAME].getText().toString()); - json.put("birth_date", inputFields[FIELD_BIRTHDAY].getText().toString()); - json.put("gender", currentGender); - json.put("country_code", currentCitizeship); - json.put("residence_country_code", currentResidence); - - if (currentDocumentsType != null) { - documentsJson = new JSONObject(); - documentsJson.put("document_no", inputFields[FIELD_CARDNUMBER].getText().toString()); - if (currentExpireDate[0] != 0) { - documentsJson.put("expiry_date", String.format(Locale.US, "%02d.%02d.%d", currentExpireDate[2], currentExpireDate[1], currentExpireDate[0])); - } else { - documentsJson.put("expiry_date", ""); - } + if (!documentOnly) { + json = new JSONObject(); + json.put("street_line1", inputFields[FIELD_STREET1].getText().toString()); + json.put("street_line2", inputFields[FIELD_STREET2].getText().toString()); + json.put("post_code", inputFields[FIELD_POSTCODE].getText().toString()); + json.put("city", inputFields[FIELD_CITY].getText().toString()); + json.put("state", inputFields[FIELD_STATE].getText().toString()); + json.put("country_code", currentCitizeship); } } catch (Exception ignore) { @@ -1001,27 +1190,23 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (documentsErrors != null) { documentsErrors.clear(); } - delegate.saveValue(currentType, null, json.toString(), currentDocumentsType, documentsJson != null ? documentsJson.toString() : null, null, selfieDocument, frontDocument, reverseLayout != null && reverseLayout.getVisibility() == View.VISIBLE ? reverseDocument : null, finishRunnable, errorRunnable); + delegate.saveValue(currentType, null, json != null ? json.toString() : null, currentDocumentsType, null, documents, selfieDocument, translationDocuments, null, null, finishRunnable, errorRunnable); + } else if (currentActivityType == TYPE_IDENTITY) { + if (!onIdentityDone(finishRunnable, errorRunnable)) { + return; + } } else if (currentActivityType == TYPE_EMAIL_VERIFICATION) { final TLRPC.TL_account_verifyEmail req = new TLRPC.TL_account_verifyEmail(); req.email = currentValues.get("email"); req.code = inputFields[FIELD_EMAIL].getText().toString(); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - delegate.saveValue(currentType, currentValues.get("email"), null, null, null, null, null, null, null, finishRunnable, errorRunnable); - } else { - AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); - errorRunnable.onError(null, null); - } - } - }); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + delegate.saveValue(currentType, currentValues.get("email"), null, null, null, null, null, null, null, null, finishRunnable, errorRunnable); + } else { + AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); + errorRunnable.onError(null, null); } - }); + })); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } else if (currentActivityType == TYPE_PHONE_VERIFICATION) { views[currentViewNum].onNextPressed(); @@ -1130,6 +1315,47 @@ public class PassportActivity extends BaseFragment implements NotificationCenter super.dismissCurrentDialig(); } + private String getTranslitString(String value) { + return LocaleController.getInstance().getTranslitString(value, true); + } + + private int getFieldCost(String key) { + switch (key) { + case "first_name": + case "first_name_native": + return 20; + case "middle_name": + case "middle_name_native": + return 21; + case "last_name": + case "last_name_native": + return 22; + case "birth_date": + return 23; + case "gender": + return 24; + case "country_code": + return 25; + case "residence_country_code": + return 26; + case "document_no": + return 27; + case "expiry_date": + return 28; + case "street_line1": + return 29; + case "street_line2": + return 30; + case "post_code": + return 31; + case "city": + return 32; + case "state": + return 33; + } + return 100; + } + private void createPhoneVerificationInterface(Context context) { actionBar.setTitle(LocaleController.getString("PassportPhone", R.string.PassportPhone)); @@ -1148,31 +1374,25 @@ public class PassportActivity extends BaseFragment implements NotificationCenter private void loadPasswordInfo() { TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - currentPassword = (TLRPC.account_Password) response; + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response != null) { + currentPassword = (TLRPC.TL_account_password) response; + if (!TwoStepVerificationActivity.canHandleCurrentPassword(currentPassword, false)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + return; + } + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + updatePasswordInterface(); - byte[] salt = new byte[currentPassword.new_salt.length + 8]; - Utilities.random.nextBytes(salt); - System.arraycopy(currentPassword.new_salt, 0, salt, 0, currentPassword.new_salt.length); - currentPassword.new_salt = salt; - - updatePasswordInterface(); - - if (inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { - inputFields[FIELD_PASSWORD].requestFocus(); - AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); - } - } - } - }); + if (inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { + inputFields[FIELD_PASSWORD].requestFocus(); + AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); + } + if (usingSavedPassword == 1) { + onPasswordDone(true); + } } - }); + })); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -1207,15 +1427,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { - doneItem.callOnClick(); - return true; - } - return false; + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { + doneItem.callOnClick(); + return true; } + return false; }); inputFields[a].addTextChangedListener(new TextWatcher() { @@ -1313,14 +1530,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter noPasswordSetTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); noPasswordSetTextView.setText(LocaleController.getString("TelegramPassportCreatePassword", R.string.TelegramPassportCreatePassword)); linearLayout2.addView(noPasswordSetTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 9, 17, 0)); - noPasswordSetTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - TwoStepVerificationActivity activity = new TwoStepVerificationActivity(currentAccount, 1); - activity.setCloseAfterSet(true); - activity.setCurrentPasswordInfo(new byte[0], currentPassword); - presentFragment(activity); - } + noPasswordSetTextView.setOnClickListener(v -> { + TwoStepVerificationActivity activity = new TwoStepVerificationActivity(currentAccount, 1); + activity.setCloseAfterSet(true); + activity.setCurrentPasswordInfo(new byte[0], currentPassword); + presentFragment(activity); }); inputFields = new EditTextBoldCursor[1]; @@ -1350,15 +1564,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); inputFieldContainers[a].addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT || i == EditorInfo.IME_ACTION_DONE) { - doneItem.callOnClick(); - return true; - } - return false; + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT || i == EditorInfo.IME_ACTION_DONE) { + doneItem.callOnClick(); + return true; } + return false; }); inputFields[a].setCustomSelectionActionModeCallback(new ActionMode.Callback() { public boolean onPrepareActionMode(ActionMode mode, Menu menu) { @@ -1389,73 +1600,54 @@ public class PassportActivity extends BaseFragment implements NotificationCenter passwordForgotButton.setText(LocaleController.getString("ForgotPassword", R.string.ForgotPassword)); passwordForgotButton.setPadding(0, 0, 0, 0); linearLayout2.addView(passwordForgotButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 30, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 17, 0)); - passwordForgotButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (currentPassword.has_recovery) { - needShowProgress(); - TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); - fragment.setRecoveryParams(currentPassword); - currentPassword.email_unconfirmed_pattern = res.email_pattern; - presentFragment(fragment); - } - }); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } else { - if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + passwordForgotButton.setOnClickListener(v -> { + if (currentPassword.has_recovery) { + needShowProgress(); + TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error == null) { + final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); + fragment.setRecoveryParams(currentPassword); + currentPassword.email_unconfirmed_pattern = res.email_pattern; + presentFragment(fragment); + }); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); + } + } else { + if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); - } else { - if (getParentActivity() == null) { - return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setNegativeButton(LocaleController.getString("RestorePasswordResetAccount", R.string.RestorePasswordResetAccount), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Browser.openUrl(getParentActivity(), "https://telegram.org/deactivate?phone=" + UserConfig.getInstance(currentAccount).getClientPhone()); - } - }); - builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); - builder.setMessage(LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); - showDialog(builder.create()); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } else { + if (getParentActivity() == null) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setNegativeButton(LocaleController.getString("RestorePasswordResetAccount", R.string.RestorePasswordResetAccount), (dialog, which) -> Browser.openUrl(getParentActivity(), "https://telegram.org/deactivate?phone=" + UserConfig.getInstance(currentAccount).getClientPhone())); + builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); + builder.setMessage(LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); + showDialog(builder.create()); } }); @@ -1463,10 +1655,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } private void onPasswordDone(final boolean saved) { - final byte[] currentPasswordHash; final String textPassword; if (saved) { - currentPasswordHash = savedPasswordHash; textPassword = null; } else { textPassword = inputFields[FIELD_PASSWORD].getText().toString(); @@ -1475,167 +1665,230 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return; } showEditDoneProgress(true, true); - byte[] passwordBytes = AndroidUtilities.getStringBytes(textPassword); - byte[] hash = new byte[currentPassword.current_salt.length * 2 + passwordBytes.length]; - System.arraycopy(currentPassword.current_salt, 0, hash, 0, currentPassword.current_salt.length); - System.arraycopy(passwordBytes, 0, hash, currentPassword.current_salt.length, passwordBytes.length); - System.arraycopy(currentPassword.current_salt, 0, hash, hash.length - currentPassword.current_salt.length, currentPassword.current_salt.length); - currentPasswordHash = Utilities.computeSHA256(hash, 0, hash.length); } - RequestDelegate requestDelegate = new RequestDelegate() { + Utilities.globalQueue.postRunnable(() -> { + TLRPC.TL_account_getPasswordSettings req = new TLRPC.TL_account_getPasswordSettings(); - private void openRequestInterface() { - if (inputFields == null) { - return; - } - if (!saved) { - UserConfig.getInstance(currentAccount).savePassword(currentPasswordHash, saltedPassword); - } - - AndroidUtilities.hideKeyboard(inputFields[FIELD_PASSWORD]); - ignoreOnFailure = true; - int type; - if (currentBotId == 0) { - type = TYPE_MANAGE; - } else { - type = TYPE_REQUEST; - } - PassportActivity activity = new PassportActivity(type, currentBotId, currentScope, currentPublicKey, currentPayload, currentCallbackUrl, currentForm, currentPassword); - activity.currentEmail = currentEmail; - activity.currentAccount = currentAccount; - activity.saltedPassword = saltedPassword; - activity.secureSecret = secureSecret; - activity.secureSecretId = secureSecretId; - activity.needActivityResult = needActivityResult; - if (parentLayout == null || !parentLayout.checkTransitionAnimation()) { - presentFragment(activity, true); - } else { - presentAfterAnimation = activity; - } + final byte x_bytes[]; + if (saved) { + x_bytes = savedPasswordHash; + } else if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + byte[] passwordBytes = AndroidUtilities.getStringBytes(textPassword); + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + x_bytes = SRPHelper.getX(passwordBytes, algo); + } else { + x_bytes = null; } - private void resetSecret() { - TLRPC.TL_account_updatePasswordSettings req = new TLRPC.TL_account_updatePasswordSettings(); - req.current_password_hash = currentPasswordHash; - req.new_settings = new TLRPC.TL_account_passwordInputSettings(); - req.new_settings.new_secure_secret = new byte[0]; - req.new_settings.new_secure_salt = new byte[0]; - req.new_settings.new_secure_secret_id = 0; - req.new_settings.flags |= 4; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - generateNewSecret(); - } - }); + RequestDelegate requestDelegate = new RequestDelegate() { + + private void openRequestInterface() { + if (inputFields == null) { + return; + } + if (!saved) { + UserConfig.getInstance(currentAccount).savePassword(x_bytes, saltedPassword); } - }); - } - private void generateNewSecret() { - Utilities.random.setSeed(currentPassword.secure_random); - byte[] secureSalt = new byte[currentPassword.new_secure_salt.length + 8]; - Utilities.random.nextBytes(secureSalt); - System.arraycopy(currentPassword.new_secure_salt, 0, secureSalt, 0, currentPassword.new_secure_salt.length); + AndroidUtilities.hideKeyboard(inputFields[FIELD_PASSWORD]); + ignoreOnFailure = true; + int type; + if (currentBotId == 0) { + type = TYPE_MANAGE; + } else { + type = TYPE_REQUEST; + } + PassportActivity activity = new PassportActivity(type, currentBotId, currentScope, currentPublicKey, currentPayload, currentCallbackUrl, currentForm, currentPassword); + activity.currentEmail = currentEmail; + activity.currentAccount = currentAccount; + activity.saltedPassword = saltedPassword; + activity.secureSecret = secureSecret; + activity.secureSecretId = secureSecretId; + activity.needActivityResult = needActivityResult; + if (parentLayout == null || !parentLayout.checkTransitionAnimation()) { + presentFragment(activity, true); + } else { + presentAfterAnimation = activity; + } + } - saltedPassword = Utilities.computeSHA512(secureSalt, AndroidUtilities.getStringBytes(textPassword), secureSalt); - byte[] key = new byte[32]; - System.arraycopy(saltedPassword, 0, key, 0, 32); - byte[] iv = new byte[16]; - System.arraycopy(saltedPassword, 32, iv, 0, 16); - - secureSecret = getRandomSecret(); - secureSecretId = Utilities.bytesToLong(Utilities.computeSHA256(secureSecret)); - Utilities.aesCbcEncryptionByteArraySafe(secureSecret, key, iv, 0, secureSecret.length, 0, 1); - - TLRPC.TL_account_updatePasswordSettings req = new TLRPC.TL_account_updatePasswordSettings(); - req.current_password_hash = currentPasswordHash; - req.new_settings = new TLRPC.TL_account_passwordInputSettings(); - req.new_settings.new_secure_secret = secureSecret; - req.new_settings.new_secure_salt = secureSalt; - req.new_settings.new_secure_secret_id = secureSecretId; - req.new_settings.flags |= 4; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (currentForm == null) { - currentForm = new TLRPC.TL_account_authorizationForm(); - currentForm.selfie_required = true; + private void resetSecret() { + TLRPC.TL_account_updatePasswordSettings req2 = new TLRPC.TL_account_updatePasswordSettings(); + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + req2.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, algo); + } + req2.new_settings = new TLRPC.TL_account_passwordInputSettings(); + req2.new_settings.new_secure_settings = new TLRPC.TL_secureSecretSettings(); + req2.new_settings.new_secure_settings.secure_secret = new byte[0]; + req2.new_settings.new_secure_settings.secure_algo = new TLRPC.TL_securePasswordKdfAlgoUnknown(); + req2.new_settings.new_secure_settings.secure_secret_id = 0; + req2.new_settings.flags |= 4; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + resetSecret(); } - openRequestInterface(); - } - }); - } - }); - } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + generateNewSecret(); + })); + } - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - TLRPC.TL_account_passwordSettings settings = (TLRPC.TL_account_passwordSettings) response; - secureSecret = settings.secure_secret; - secureSecretId = settings.secure_secret_id; - currentEmail = settings.email; - if (saved) { - saltedPassword = savedSaltedPassword; - } else { - saltedPassword = Utilities.computeSHA512(settings.secure_salt, AndroidUtilities.getStringBytes(textPassword), settings.secure_salt); - } + private void generateNewSecret() { + Utilities.globalQueue.postRunnable(() -> { + Utilities.random.setSeed(currentPassword.secure_random); - if (!checkSecret(decryptSecret(secureSecret, saltedPassword), secureSecretId) || settings.secure_salt.length == 0 || secureSecretId == 0) { - if (saved) { - UserConfig.getInstance(currentAccount).resetSavedPassword(); - usingSavedPassword = 0; - updatePasswordInterface(); - } else { - if (secureSecret == null || secureSecret.length == 0) { + TLRPC.TL_account_updatePasswordSettings req1 = new TLRPC.TL_account_updatePasswordSettings(); + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + req1.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, algo); + } + req1.new_settings = new TLRPC.TL_account_passwordInputSettings(); + + secureSecret = getRandomSecret(); + secureSecretId = Utilities.bytesToLong(Utilities.computeSHA256(secureSecret)); + if (currentPassword.new_secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 newAlgo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) currentPassword.new_secure_algo; + + saltedPassword = Utilities.computePBKDF2(AndroidUtilities.getStringBytes(textPassword), newAlgo.salt); + byte[] key = new byte[32]; + System.arraycopy(saltedPassword, 0, key, 0, 32); + byte[] iv = new byte[16]; + System.arraycopy(saltedPassword, 32, iv, 0, 16); + + Utilities.aesCbcEncryptionByteArraySafe(secureSecret, key, iv, 0, secureSecret.length, 0, 1); + + req1.new_settings.new_secure_settings = new TLRPC.TL_secureSecretSettings(); + req1.new_settings.new_secure_settings.secure_algo = newAlgo; + req1.new_settings.new_secure_settings.secure_secret = secureSecret; + req1.new_settings.new_secure_settings.secure_secret_id = secureSecretId; + req1.new_settings.flags |= 4; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req1, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); generateNewSecret(); - } else { - resetSecret(); } - } - } else if (currentBotId == 0) { - TLRPC.TL_account_getAllSecureValues req = new TLRPC.TL_account_getAllSecureValues(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - currentForm = new TLRPC.TL_account_authorizationForm(); - currentForm.selfie_required = true; - TLRPC.Vector vector = (TLRPC.Vector) response; - for (int a = 0, size = vector.objects.size(); a < size; a++) { - currentForm.values.add((TLRPC.TL_secureValue) vector.objects.get(a)); - } - openRequestInterface(); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - }); - } - }); - } else { - openRequestInterface(); + }), ConnectionsManager.RequestFlagWithoutLogin); + return; } - } else { + if (currentForm == null) { + currentForm = new TLRPC.TL_account_authorizationForm(); + } + openRequestInterface(); + })); + }); + } + + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + onPasswordDone(saved); + } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + if (error == null) { + Utilities.globalQueue.postRunnable(() -> { + TLRPC.TL_account_passwordSettings settings = (TLRPC.TL_account_passwordSettings) response; + byte[] secure_salt; + if (settings.secure_settings != null) { + secureSecret = settings.secure_settings.secure_secret; + secureSecretId = settings.secure_settings.secure_secret_id; + if (settings.secure_settings.secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoSHA512) { + TLRPC.TL_securePasswordKdfAlgoSHA512 algo = (TLRPC.TL_securePasswordKdfAlgoSHA512) settings.secure_settings.secure_algo; + secure_salt = algo.salt; + saltedPassword = Utilities.computeSHA512(secure_salt, AndroidUtilities.getStringBytes(textPassword), secure_salt); + } else if (settings.secure_settings.secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 algo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) settings.secure_settings.secure_algo; + secure_salt = algo.salt; + saltedPassword = Utilities.computePBKDF2(AndroidUtilities.getStringBytes(textPassword), algo.salt); + } else if (settings.secure_settings.secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoUnknown) { + AndroidUtilities.runOnUIThread(() -> AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true)); + return; + } else { + secure_salt = new byte[0]; + } + } else { + if (currentPassword.new_secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 algo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) currentPassword.new_secure_algo; + secure_salt = algo.salt; + saltedPassword = Utilities.computePBKDF2(AndroidUtilities.getStringBytes(textPassword), algo.salt); + } else { + secure_salt = new byte[0]; + } + secureSecret = null; + secureSecretId = 0; + } + AndroidUtilities.runOnUIThread(() -> { + currentEmail = settings.email; + if (saved) { + saltedPassword = savedSaltedPassword; + } + + if (!checkSecret(decryptSecret(secureSecret, saltedPassword), secureSecretId) || secure_salt.length == 0 || secureSecretId == 0) { + if (saved) { + UserConfig.getInstance(currentAccount).resetSavedPassword(); + usingSavedPassword = 0; + updatePasswordInterface(); + } else { + if (currentForm != null) { + currentForm.values.clear(); + currentForm.errors.clear(); + } + if (secureSecret == null || secureSecret.length == 0) { + generateNewSecret(); + } else { + resetSecret(); + } + } + } else if (currentBotId == 0) { + TLRPC.TL_account_getAllSecureValues req12 = new TLRPC.TL_account_getAllSecureValues(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req12, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { + if (response1 != null) { + currentForm = new TLRPC.TL_account_authorizationForm(); + TLRPC.Vector vector = (TLRPC.Vector) response1; + for (int a = 0, size = vector.objects.size(); a < size; a++) { + currentForm.values.add((TLRPC.TL_secureValue) vector.objects.get(a)); + } + openRequestInterface(); + } else { + if ("APP_VERSION_OUTDATED".equals(error1.text)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error1.text); + } + showEditDoneProgress(true, false); + } + })); + } else { + openRequestInterface(); + } + }); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { if (saved) { UserConfig.getInstance(currentAccount).resetSavedPassword(); usingSavedPassword = 0; updatePasswordInterface(); - if (inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { + if (inputFieldContainers != null && inputFieldContainers[FIELD_PASSWORD].getVisibility() == View.VISIBLE) { inputFields[FIELD_PASSWORD].requestFocus(); AndroidUtilities.showKeyboard(inputFields[FIELD_PASSWORD]); } @@ -1656,16 +1909,43 @@ public class PassportActivity extends BaseFragment implements NotificationCenter showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); } } - } + }); } - }); - } - }; + } + }; - TLRPC.TL_account_getPasswordSettings req = new TLRPC.TL_account_getPasswordSettings(); - req.current_password_hash = currentPasswordHash; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + req.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, algo); + if (req.password == null) { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "ALGO_INVALID"; + requestDelegate.run(null, error); + return; + } + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } else { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error); + } + }); + } + + private boolean isPersonalDocument(TLRPC.SecureValueType type) { + return type instanceof TLRPC.TL_secureValueTypeDriverLicense || + type instanceof TLRPC.TL_secureValueTypePassport || + type instanceof TLRPC.TL_secureValueTypeInternalPassport || + type instanceof TLRPC.TL_secureValueTypeIdentityCard; + } + + private boolean isAddressDocument(TLRPC.SecureValueType type) { + return type instanceof TLRPC.TL_secureValueTypeUtilityBill || + type instanceof TLRPC.TL_secureValueTypeBankStatement || + type instanceof TLRPC.TL_secureValueTypePassportRegistration || + type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || + type instanceof TLRPC.TL_secureValueTypeRentalAgreement; } private void createRequestInterface(Context context) { @@ -1715,38 +1995,137 @@ public class PassportActivity extends BaseFragment implements NotificationCenter linearLayout2.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); if (currentForm != null) { - for (int a = 0, size = currentForm.required_types.size(); a < size; a++) { - TLRPC.SecureValueType type = currentForm.required_types.get(a); - ArrayList documentTypes; - if (type instanceof TLRPC.TL_secureValueTypePhone || type instanceof TLRPC.TL_secureValueTypeEmail) { - documentTypes = null; - } else if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { - documentTypes = new ArrayList<>(); - for (int b = 0; b < size; b++) { - TLRPC.SecureValueType innerType = currentForm.required_types.get(b); - if (innerType instanceof TLRPC.TL_secureValueTypeDriverLicense || - innerType instanceof TLRPC.TL_secureValueTypePassport || - innerType instanceof TLRPC.TL_secureValueTypeInternalPassport || - innerType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - documentTypes.add(innerType); - } + int size = currentForm.required_types.size(); + ArrayList personalDocuments = new ArrayList<>(); + ArrayList addressDocuments = new ArrayList<>(); + int personalCount = 0; + int addressCount = 0; + boolean hasPersonalInfo = false; + boolean hasAddressInfo = false; + for (int a = 0; a < size; a++) { + TLRPC.SecureRequiredType secureRequiredType = currentForm.required_types.get(a); + if (secureRequiredType instanceof TLRPC.TL_secureRequiredType) { + TLRPC.TL_secureRequiredType requiredType = (TLRPC.TL_secureRequiredType) secureRequiredType; + if (isPersonalDocument(requiredType.type)) { + personalDocuments.add(requiredType); + personalCount++; + } else if (isAddressDocument(requiredType.type)) { + addressDocuments.add(requiredType); + addressCount++; + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + hasPersonalInfo = true; + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + hasAddressInfo = true; } - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { - documentTypes = new ArrayList<>(); - for (int b = 0; b < size; b++) { - TLRPC.SecureValueType innerType = currentForm.required_types.get(b); - if (innerType instanceof TLRPC.TL_secureValueTypeUtilityBill || - innerType instanceof TLRPC.TL_secureValueTypeBankStatement || - innerType instanceof TLRPC.TL_secureValueTypePassportRegistration || - innerType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || - innerType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - documentTypes.add(innerType); + } else if (secureRequiredType instanceof TLRPC.TL_secureRequiredTypeOneOf) { + TLRPC.TL_secureRequiredTypeOneOf requiredTypeOneOf = (TLRPC.TL_secureRequiredTypeOneOf) secureRequiredType; + if (requiredTypeOneOf.types.isEmpty()) { + continue; + } + TLRPC.SecureRequiredType innerType = requiredTypeOneOf.types.get(0); + if (!(innerType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + TLRPC.TL_secureRequiredType requiredType = (TLRPC.TL_secureRequiredType) innerType; + + if (isPersonalDocument(requiredType.type)) { + for (int b = 0, size2 = requiredTypeOneOf.types.size(); b < size2; b++) { + innerType = requiredTypeOneOf.types.get(b); + if (!(innerType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + personalDocuments.add((TLRPC.TL_secureRequiredType) innerType); } + personalCount++; + } else if (isAddressDocument(requiredType.type)) { + for (int b = 0, size2 = requiredTypeOneOf.types.size(); b < size2; b++) { + innerType = requiredTypeOneOf.types.get(b); + if (!(innerType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + addressDocuments.add((TLRPC.TL_secureRequiredType) innerType); + } + addressCount++; + } + } + } + boolean separatePersonal = !hasPersonalInfo || personalCount > 1; + boolean separateAddress = !hasAddressInfo || addressCount > 1; + for (int a = 0; a < size; a++) { + TLRPC.SecureRequiredType secureRequiredType = currentForm.required_types.get(a); + ArrayList documentTypes; + TLRPC.TL_secureRequiredType requiredType; + boolean documentOnly; + if (secureRequiredType instanceof TLRPC.TL_secureRequiredType) { + requiredType = (TLRPC.TL_secureRequiredType) secureRequiredType; + if (requiredType.type instanceof TLRPC.TL_secureValueTypePhone || requiredType.type instanceof TLRPC.TL_secureValueTypeEmail) { + documentTypes = null; + documentOnly = false; + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (separatePersonal) { + documentTypes = null; + } else { + documentTypes = personalDocuments; + } + documentOnly = false; + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + if (separateAddress) { + documentTypes = null; + } else { + documentTypes = addressDocuments; + } + documentOnly = false; + } else if (separatePersonal && isPersonalDocument(requiredType.type)) { + documentTypes = new ArrayList<>(); + documentTypes.add(requiredType); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypePersonalDetails(); + documentOnly = true; + } else if (separateAddress && isAddressDocument(requiredType.type)) { + documentTypes = new ArrayList<>(); + documentTypes.add(requiredType); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypeAddress(); + documentOnly = true; + } else { + continue; + } + } else if (secureRequiredType instanceof TLRPC.TL_secureRequiredTypeOneOf) { + TLRPC.TL_secureRequiredTypeOneOf requiredTypeOneOf = (TLRPC.TL_secureRequiredTypeOneOf) secureRequiredType; + if (requiredTypeOneOf.types.isEmpty()) { + continue; + } + TLRPC.SecureRequiredType innerType = requiredTypeOneOf.types.get(0); + if (!(innerType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + requiredType = (TLRPC.TL_secureRequiredType) innerType; + + if (separatePersonal && isPersonalDocument(requiredType.type) || separateAddress && isAddressDocument(requiredType.type)) { + documentTypes = new ArrayList<>(); + for (int b = 0, size2 = requiredTypeOneOf.types.size(); b < size2; b++) { + innerType = requiredTypeOneOf.types.get(b); + if (!(innerType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + documentTypes.add((TLRPC.TL_secureRequiredType) innerType); + } + if (isPersonalDocument(requiredType.type)) { + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypePersonalDetails(); + } else { + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypeAddress(); + } + + documentOnly = true; + } else { + continue; } } else { continue; } - addField(context, currentForm.required_types.get(a), documentTypes, a == size - 1); + addField(context, requiredType, documentTypes, documentOnly, a == size - 1); } } @@ -1777,210 +2156,215 @@ public class PassportActivity extends BaseFragment implements NotificationCenter bottomLayout = new FrameLayout(context); bottomLayout.setBackgroundDrawable(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_passport_authorizeBackground), Theme.getColor(Theme.key_passport_authorizeBackgroundSelected))); frameLayout.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); - bottomLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - ArrayList valuesToSend = new ArrayList<>(); - for (int a = 0, size = currentForm.required_types.size(); a < size; a++) { - TLRPC.SecureValueType type = currentForm.required_types.get(a); - TLRPC.SecureValueType innerType = null; - boolean needDocuments = false; - TLRPC.TL_secureValue documentValue = null; - if (type instanceof TLRPC.TL_secureValueTypePhone || type instanceof TLRPC.TL_secureValueTypeEmail) { - needDocuments = false; - } else if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { - for (int b = 0; b < size; b++) { - innerType = currentForm.required_types.get(b); - if (innerType instanceof TLRPC.TL_secureValueTypeDriverLicense || - innerType instanceof TLRPC.TL_secureValueTypePassport || - innerType instanceof TLRPC.TL_secureValueTypeInternalPassport || - innerType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - needDocuments = true; - documentValue = getValueByType(innerType, true); - if (documentValue != null) { - break; - } - } - } - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { - for (int b = 0; b < size; b++) { - innerType = currentForm.required_types.get(b); - if (innerType instanceof TLRPC.TL_secureValueTypeUtilityBill || - innerType instanceof TLRPC.TL_secureValueTypeBankStatement || - innerType instanceof TLRPC.TL_secureValueTypePassportRegistration || - innerType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || - innerType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - needDocuments = true; - documentValue = getValueByType(innerType, true); - if (documentValue != null) { - break; - } - } - } - } else { + bottomLayout.setOnClickListener(view -> { + + class ValueToSend { + TLRPC.TL_secureValue value; + boolean selfie_required; + boolean translation_required; + + public ValueToSend(TLRPC.TL_secureValue v, boolean s, boolean t) { + value = v; + selfie_required = s; + translation_required = t; + } + } + + ArrayList valuesToSend = new ArrayList<>(); + for (int a = 0, size = currentForm.required_types.size(); a < size; a++) { + + TLRPC.TL_secureRequiredType requiredType; + + TLRPC.SecureRequiredType secureRequiredType = currentForm.required_types.get(a); + if (secureRequiredType instanceof TLRPC.TL_secureRequiredType) { + requiredType = (TLRPC.TL_secureRequiredType) secureRequiredType; + } else if (secureRequiredType instanceof TLRPC.TL_secureRequiredTypeOneOf) { + TLRPC.TL_secureRequiredTypeOneOf requiredTypeOneOf = (TLRPC.TL_secureRequiredTypeOneOf) secureRequiredType; + if (requiredTypeOneOf.types.isEmpty()) { continue; } - TLRPC.TL_secureValue value = getValueByType(type, true); - if (value == null || documentValue == null && needDocuments) { - Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); - if (v != null) { - v.vibrate(200); + secureRequiredType = requiredTypeOneOf.types.get(0); + if (!(secureRequiredType instanceof TLRPC.TL_secureRequiredType)) { + continue; + } + requiredType = (TLRPC.TL_secureRequiredType) secureRequiredType; + + for (int b = 0, size2 = requiredTypeOneOf.types.size(); b < size2; b++) { + secureRequiredType = requiredTypeOneOf.types.get(b); + if (!(secureRequiredType instanceof TLRPC.TL_secureRequiredType)) { + continue; } - AndroidUtilities.shakeView(typesViews.get(type), 2, 0); - return; - } - String key = getNameForType(type); - String key2 = innerType != null ? getNameForType(innerType) : null; - HashMap errors = errorsMap.get(key); - HashMap errors2 = key2 != null ? errorsMap.get(key2) : null; - if (errors != null && !errors.isEmpty() || errors2 != null && !errors2.isEmpty()) { - Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); - if (v != null) { - v.vibrate(200); + TLRPC.TL_secureRequiredType innerType = (TLRPC.TL_secureRequiredType) secureRequiredType; + if (getValueByType(innerType, true) != null) { + requiredType = innerType; + break; } - AndroidUtilities.shakeView(typesViews.get(type), 2, 0); - return; - } - valuesToSend.add(value); - if (documentValue != null) { - valuesToSend.add(documentValue); } + } else { + continue; } - showEditDoneProgress(false, true); - TLRPC.TL_account_acceptAuthorization req = new TLRPC.TL_account_acceptAuthorization(); - req.bot_id = currentBotId; - req.scope = currentScope; - req.public_key = currentPublicKey; - JSONObject jsonObject = new JSONObject(); - for (int a = 0, size = valuesToSend.size(); a < size; a++) { - TLRPC.TL_secureValue secureValue = valuesToSend.get(a); - JSONObject data = new JSONObject(); - - if (secureValue.plain_data != null) { - if (secureValue.plain_data instanceof TLRPC.TL_securePlainEmail) { - TLRPC.TL_securePlainEmail securePlainEmail = (TLRPC.TL_securePlainEmail) secureValue.plain_data; - } else if (secureValue.plain_data instanceof TLRPC.TL_securePlainPhone) { - TLRPC.TL_securePlainPhone securePlainPhone = (TLRPC.TL_securePlainPhone) secureValue.plain_data; - } - } else { - try { - JSONObject result = new JSONObject(); - if (secureValue.data != null) { - byte[] decryptedSecret = decryptValueSecret(secureValue.data.secret, secureValue.data.data_hash); - - data.put("data_hash", Base64.encodeToString(secureValue.data.data_hash, Base64.NO_WRAP)); - data.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); - - result.put("data", data); - } - if (!secureValue.files.isEmpty()) { - JSONArray files = new JSONArray(); - for (int b = 0, size2 = secureValue.files.size(); b < size2; b++) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.files.get(b); - byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); - - JSONObject file = new JSONObject(); - file.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); - file.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); - files.put(file); - } - result.put("files", files); - } - if (secureValue.front_side instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.front_side; - byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); - - JSONObject front = new JSONObject(); - front.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); - front.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); - result.put("front_side", front); - } - if (secureValue.reverse_side instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.reverse_side; - byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); - - JSONObject reverse = new JSONObject(); - reverse.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); - reverse.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); - result.put("reverse_side", reverse); - } - if (currentForm.selfie_required && secureValue.selfie instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.selfie; - byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); - - JSONObject selfie = new JSONObject(); - selfie.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); - selfie.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); - result.put("selfie", selfie); - } - jsonObject.put(getNameForType(secureValue.type), result); - } catch (Exception ignore) { - - } + TLRPC.TL_secureValue value = getValueByType(requiredType, true); + if (value == null) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); } - - TLRPC.TL_secureValueHash hash = new TLRPC.TL_secureValueHash(); - hash.type = secureValue.type; - hash.hash = secureValue.hash; - req.value_hashes.add(hash); + AndroidUtilities.shakeView(getViewByType(requiredType), 2, 0); + return; } - JSONObject result = new JSONObject(); - try { - result.put("secure_data", jsonObject); - } catch (Exception ignore) { - + String key = getNameForType(requiredType.type); + HashMap errors = errorsMap.get(key); + if (errors != null && !errors.isEmpty()) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(getViewByType(requiredType), 2, 0); + return; } - if (currentPayload != null) { + valuesToSend.add(new ValueToSend(value, requiredType.selfie_required, requiredType.translation_required)); + } + showEditDoneProgress(false, true); + TLRPC.TL_account_acceptAuthorization req = new TLRPC.TL_account_acceptAuthorization(); + req.bot_id = currentBotId; + req.scope = currentScope; + req.public_key = currentPublicKey; + JSONObject jsonObject = new JSONObject(); + for (int a = 0, size = valuesToSend.size(); a < size; a++) { + ValueToSend valueToSend = valuesToSend.get(a); + TLRPC.TL_secureValue secureValue = valueToSend.value; + + JSONObject data = new JSONObject(); + + if (secureValue.plain_data != null) { + if (secureValue.plain_data instanceof TLRPC.TL_securePlainEmail) { + TLRPC.TL_securePlainEmail securePlainEmail = (TLRPC.TL_securePlainEmail) secureValue.plain_data; + } else if (secureValue.plain_data instanceof TLRPC.TL_securePlainPhone) { + TLRPC.TL_securePlainPhone securePlainPhone = (TLRPC.TL_securePlainPhone) secureValue.plain_data; + } + } else { try { - result.put("payload", currentPayload); + JSONObject result = new JSONObject(); + if (secureValue.data != null) { + byte[] decryptedSecret = decryptValueSecret(secureValue.data.secret, secureValue.data.data_hash); + + data.put("data_hash", Base64.encodeToString(secureValue.data.data_hash, Base64.NO_WRAP)); + data.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + + result.put("data", data); + } + if (!secureValue.files.isEmpty()) { + JSONArray files = new JSONArray(); + for (int b = 0, size2 = secureValue.files.size(); b < size2; b++) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.files.get(b); + byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); + + JSONObject file = new JSONObject(); + file.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); + file.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + files.put(file); + } + result.put("files", files); + } + if (secureValue.front_side instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.front_side; + byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); + + JSONObject front = new JSONObject(); + front.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); + front.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + result.put("front_side", front); + } + if (secureValue.reverse_side instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.reverse_side; + byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); + + JSONObject reverse = new JSONObject(); + reverse.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); + reverse.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + result.put("reverse_side", reverse); + } + if (valueToSend.selfie_required && secureValue.selfie instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.selfie; + byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); + + JSONObject selfie = new JSONObject(); + selfie.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); + selfie.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + result.put("selfie", selfie); + } + if (valueToSend.translation_required && !secureValue.translation.isEmpty()) { + JSONArray translation = new JSONArray(); + for (int b = 0, size2 = secureValue.translation.size(); b < size2; b++) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) secureValue.translation.get(b); + byte[] decryptedSecret = decryptValueSecret(secureFile.secret, secureFile.file_hash); + + JSONObject file = new JSONObject(); + file.put("file_hash", Base64.encodeToString(secureFile.file_hash, Base64.NO_WRAP)); + file.put("secret", Base64.encodeToString(decryptedSecret, Base64.NO_WRAP)); + translation.put(file); + } + result.put("translation", translation); + } + jsonObject.put(getNameForType(secureValue.type), result); } catch (Exception ignore) { } } - String json = result.toString(); - EncryptionResult encryptionResult = encryptData(AndroidUtilities.getStringBytes(json)); - - req.credentials = new TLRPC.TL_secureCredentialsEncrypted(); - req.credentials.hash = encryptionResult.fileHash; - req.credentials.data = encryptionResult.encryptedData; - try { - String key = currentPublicKey.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", ""); - KeyFactory kf = KeyFactory.getInstance("RSA"); - X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)); - RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509); - - Cipher c = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); - c.init(Cipher.ENCRYPT_MODE, pubKey); - req.credentials.secret = c.doFinal(encryptionResult.decrypyedFileSecret); - } catch (Exception e) { - FileLog.e(e); - } - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - ignoreOnFailure = true; - callCallback(true); - finishFragment(); - } else { - showEditDoneProgress(false, false); - if ("APP_VERSION_OUTDATED".equals(error.text)) { - AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); - } - }); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + TLRPC.TL_secureValueHash hash = new TLRPC.TL_secureValueHash(); + hash.type = secureValue.type; + hash.hash = secureValue.hash; + req.value_hashes.add(hash); } + JSONObject result = new JSONObject(); + try { + result.put("secure_data", jsonObject); + } catch (Exception ignore) { + + } + if (currentPayload != null) { + try { + result.put("payload", currentPayload); + } catch (Exception ignore) { + + } + } + String json = result.toString(); + + EncryptionResult encryptionResult = encryptData(AndroidUtilities.getStringBytes(json)); + + req.credentials = new TLRPC.TL_secureCredentialsEncrypted(); + req.credentials.hash = encryptionResult.fileHash; + req.credentials.data = encryptionResult.encryptedData; + try { + String key = currentPublicKey.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", ""); + KeyFactory kf = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)); + RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509); + + Cipher c = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + c.init(Cipher.ENCRYPT_MODE, pubKey); + req.credentials.secret = c.doFinal(encryptionResult.decrypyedFileSecret); + } catch (Exception e) { + FileLog.e(e); + } + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + ignoreOnFailure = true; + callCallback(true); + finishFragment(); + } else { + showEditDoneProgress(false, false); + if ("APP_VERSION_OUTDATED".equals(error.text)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); + } + } + })); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); }); acceptTextView = new TextView(context); @@ -2022,59 +2406,40 @@ public class PassportActivity extends BaseFragment implements NotificationCenter addDocumentCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); addDocumentCell.setText(LocaleController.getString("PassportNoDocumentsAdd", R.string.PassportNoDocumentsAdd), true); linearLayout2.addView(addDocumentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - addDocumentCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - openAddDocumentAlert(); - } - }); + addDocumentCell.setOnClickListener(v -> openAddDocumentAlert()); deletePassportCell = new TextSettingsCell(context); deletePassportCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); deletePassportCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); deletePassportCell.setText(LocaleController.getString("TelegramPassportDelete", R.string.TelegramPassportDelete), false); linearLayout2.addView(deletePassportCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - deletePassportCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - TLRPC.TL_account_deleteSecureValue req = new TLRPC.TL_account_deleteSecureValue(); - for (int a = 0; a < currentForm.values.size(); a++) { - req.types.add(currentForm.values.get(a).type); + deletePassportCell.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + TLRPC.TL_account_deleteSecureValue req = new TLRPC.TL_account_deleteSecureValue(); + for (int a = 0; a < currentForm.values.size(); a++) { + req.types.add(currentForm.values.get(a).type); + } + needShowProgress(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + for (int a = 0; a < linearLayout2.getChildCount(); a++) { + View child = linearLayout2.getChildAt(a); + if (child instanceof TextDetailSecureCell) { + linearLayout2.removeView(child); + a--; } - needShowProgress(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < linearLayout2.getChildCount(); a++) { - View child = linearLayout2.getChildAt(a); - if (child instanceof TextDetailSecureCell) { - linearLayout2.removeView(child); - a--; - } - } - needHideProgress(); - typesViews.clear(); - typesValues.clear(); - currentForm.values.clear(); - updateManageVisibility(); - } - }); - } - }); } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("TelegramPassportDeleteAlert", R.string.TelegramPassportDeleteAlert)); - showDialog(builder.create()); - } + needHideProgress(); + typesViews.clear(); + typesValues.clear(); + currentForm.values.clear(); + updateManageVisibility(); + })); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("TelegramPassportDeleteAlert", R.string.TelegramPassportDeleteAlert)); + showDialog(builder.create()); }); addDocumentSectionCell = new ShadowSectionCell(context); @@ -2085,7 +2450,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter emptyLayout.setOrientation(LinearLayout.VERTICAL); emptyLayout.setGravity(Gravity.CENTER); emptyLayout.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - linearLayout2.addView(emptyLayout, new LinearLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight())); + if (AndroidUtilities.isTablet()) { + linearLayout2.addView(emptyLayout, new LinearLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(528) - ActionBar.getCurrentActionBarHeight())); + } else { + linearLayout2.addView(emptyLayout, new LinearLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight())); + } emptyImageView = new ImageView(context); emptyImageView.setImageResource(R.drawable.no_passport); @@ -2116,37 +2485,39 @@ public class PassportActivity extends BaseFragment implements NotificationCenter emptyTextView3.setGravity(Gravity.CENTER); emptyTextView3.setText(LocaleController.getString("PassportNoDocumentsAdd", R.string.PassportNoDocumentsAdd).toUpperCase()); emptyLayout.addView(emptyTextView3, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 30, Gravity.CENTER, 0, 16, 0, 0)); - emptyTextView3.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - openAddDocumentAlert(); - } - }); + emptyTextView3.setOnClickListener(v -> openAddDocumentAlert()); for (int a = 0, size = currentForm.values.size(); a < size; a++) { TLRPC.TL_secureValue value = currentForm.values.get(a); - TLRPC.SecureValueType type; - ArrayList documentTypes; - if (value.type instanceof TLRPC.TL_secureValueTypeDriverLicense || - value.type instanceof TLRPC.TL_secureValueTypePassport || - value.type instanceof TLRPC.TL_secureValueTypeInternalPassport || - value.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { - type = new TLRPC.TL_secureValueTypePersonalDetails(); + TLRPC.TL_secureRequiredType requiredType; + ArrayList documentTypes; + boolean documentOnly; + if (isPersonalDocument(value.type)) { documentTypes = new ArrayList<>(); - documentTypes.add(value.type); - } else if (value.type instanceof TLRPC.TL_secureValueTypeUtilityBill || - value.type instanceof TLRPC.TL_secureValueTypeBankStatement || - value.type instanceof TLRPC.TL_secureValueTypePassportRegistration || - value.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || - value.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - type = new TLRPC.TL_secureValueTypeAddress(); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = value.type; + requiredType.selfie_required = true; + requiredType.translation_required = true; + documentTypes.add(requiredType); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypePersonalDetails(); + documentOnly = true; + } else if (isAddressDocument(value.type)) { documentTypes = new ArrayList<>(); - documentTypes.add(value.type); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = value.type; + requiredType.translation_required = true; + documentTypes.add(requiredType); + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypeAddress(); + documentOnly = true; } else { - type = value.type; + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = value.type; documentTypes = null; + documentOnly = false; } - addField(context, type, documentTypes, a == size - 1); + addField(context, requiredType, documentTypes, documentOnly, a == size - 1); } updateManageVisibility(); @@ -2239,34 +2610,29 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("PassportNoDocumentsAdd", R.string.PassportNoDocumentsAdd)); - builder.setItems(values.toArray(new CharSequence[values.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - TLRPC.SecureValueType type = null; - TLRPC.SecureValueType documentType = null; - try { - type = types.get(which).newInstance(); - } catch (Exception ignore) { + builder.setItems(values.toArray(new CharSequence[values.size()]), (dialog, which) -> { + TLRPC.TL_secureRequiredType requiredType = null; + TLRPC.TL_secureRequiredType documentRequiredType = null; + try { + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = types.get(which).newInstance(); + } catch (Exception ignore) { - } - - if (type instanceof TLRPC.TL_secureValueTypeDriverLicense || - type instanceof TLRPC.TL_secureValueTypePassport || - type instanceof TLRPC.TL_secureValueTypeInternalPassport || - type instanceof TLRPC.TL_secureValueTypeIdentityCard) { - documentType = type; - type = new TLRPC.TL_secureValueTypePersonalDetails(); - } else if (type instanceof TLRPC.TL_secureValueTypeUtilityBill || - type instanceof TLRPC.TL_secureValueTypeBankStatement || - type instanceof TLRPC.TL_secureValueTypePassportRegistration || - type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || - type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - documentType = type; - type = new TLRPC.TL_secureValueTypeAddress(); - } - - openTypeActivity(type, documentType, new ArrayList()); } + + if (isPersonalDocument(requiredType.type)) { + documentRequiredType = requiredType; + documentRequiredType.selfie_required = true; + documentRequiredType.translation_required = true; + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypePersonalDetails(); + } else if (isAddressDocument(requiredType.type)) { + documentRequiredType = requiredType; + requiredType = new TLRPC.TL_secureRequiredType(); + requiredType.type = new TLRPC.TL_secureValueTypeAddress(); + } + + openTypeActivity(requiredType, documentRequiredType, new ArrayList<>(), documentRequiredType != null); }); showDialog(builder.create()); } @@ -2321,13 +2687,10 @@ public class PassportActivity extends BaseFragment implements NotificationCenter settingsCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); settingsCell1.setText(LocaleController.formatString("PassportPhoneUseSame", R.string.PassportPhoneUseSame, currentEmail), false); linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - useCurrentValue = true; - doneItem.callOnClick(); - useCurrentValue = false; - } + settingsCell1.setOnClickListener(v -> { + useCurrentValue = true; + doneItem.callOnClick(); + useCurrentValue = false; }); bottomCell = new TextInfoPrivacyCell(context); @@ -2370,15 +2733,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { - doneItem.callOnClick(); - return true; - } - return false; + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { + doneItem.callOnClick(); + return true; } + return false; }); } @@ -2410,12 +2770,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter FileLog.e(e); } - Collections.sort(countriesArray, new Comparator() { - @Override - public int compare(String lhs, String rhs) { - return lhs.compareTo(rhs); - } - }); + Collections.sort(countriesArray, String::compareTo); String currentPhone = UserConfig.getInstance(currentAccount).getCurrentUser().phone; TextSettingsCell settingsCell1 = new TextSettingsCell(context); @@ -2423,13 +2778,10 @@ public class PassportActivity extends BaseFragment implements NotificationCenter settingsCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); settingsCell1.setText(LocaleController.formatString("PassportPhoneUseSame", R.string.PassportPhoneUseSame, PhoneFormat.getInstance().format("+" + currentPhone)), false); linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - useCurrentValue = true; - doneItem.callOnClick(); - useCurrentValue = false; - } + settingsCell1.setOnClickListener(v -> { + useCurrentValue = true; + doneItem.callOnClick(); + useCurrentValue = false; }); bottomCell = new TextInfoPrivacyCell(context); @@ -2474,41 +2826,30 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setCursorSize(AndroidUtilities.dp(20)); inputFields[a].setCursorWidth(1.5f); if (a == FIELD_PHONECOUNTRY) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - CountrySelectActivity fragment = new CountrySelectActivity(false); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - inputFields[FIELD_PHONECOUNTRY].setText(name); - int index = countriesArray.indexOf(name); - if (index != -1) { - ignoreOnTextChange = true; - String code = countriesMap.get(name); - inputFields[FIELD_PHONECODE].setText(code); - String hint = phoneFormatMap.get(code); - inputFields[FIELD_PHONE].setHintText(hint != null ? hint.replace('X', '–') : null); - ignoreOnTextChange = false; - } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AndroidUtilities.showKeyboard(inputFields[FIELD_PHONE]); - } - }, 300); - inputFields[FIELD_PHONE].requestFocus(); - inputFields[FIELD_PHONE].setSelection(inputFields[FIELD_PHONE].length()); - } - }); - presentFragment(fragment); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + CountrySelectActivity fragment = new CountrySelectActivity(false); + fragment.setCountrySelectActivityDelegate((name, shortName) -> { + inputFields[FIELD_PHONECOUNTRY].setText(name); + int index = countriesArray.indexOf(name); + if (index != -1) { + ignoreOnTextChange = true; + String code = countriesMap.get(name); + inputFields[FIELD_PHONECODE].setText(code); + String hint = phoneFormatMap.get(code); + inputFields[FIELD_PHONE].setHintText(hint != null ? hint.replace('X', '–') : null); + ignoreOnTextChange = false; + } + AndroidUtilities.runOnUIThread(() -> AndroidUtilities.showKeyboard(inputFields[FIELD_PHONE]), 300); + inputFields[FIELD_PHONE].requestFocus(); + inputFields[FIELD_PHONE].setSelection(inputFields[FIELD_PHONE].length()); + }); + presentFragment(fragment); + } + return true; }); inputFields[a].setText(LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); inputFields[a].setInputType(0); @@ -2697,18 +3038,15 @@ public class PassportActivity extends BaseFragment implements NotificationCenter container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); } - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - inputFields[FIELD_PHONE].requestFocus(); - return true; - } else if (i == EditorInfo.IME_ACTION_DONE) { - doneItem.callOnClick(); - return true; - } - return false; + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + inputFields[FIELD_PHONE].requestFocus(); + return true; + } else if (i == EditorInfo.IME_ACTION_DONE) { + doneItem.callOnClick(); + return true; } + return false; }); if (a == FIELD_PHONECOUNTRY) { @@ -2759,21 +3097,25 @@ public class PassportActivity extends BaseFragment implements NotificationCenter FileLog.e(e); } - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentRentalAgreement", R.string.ActionBotDocumentRentalAgreement)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeBankStatement) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentBankStatement", R.string.ActionBotDocumentBankStatement)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeUtilityBill) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentUtilityBill", R.string.ActionBotDocumentUtilityBill)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypePassportRegistration) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentPassportRegistration", R.string.ActionBotDocumentPassportRegistration)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentTemporaryRegistration", R.string.ActionBotDocumentTemporaryRegistration)); - } else { - actionBar.setTitle(LocaleController.getString("PassportAddress", R.string.PassportAddress)); - } + topErrorCell = new TextInfoPrivacyCell(context); + topErrorCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + topErrorCell.setPadding(0, AndroidUtilities.dp(7), 0, 0); + linearLayout2.addView(topErrorCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + checkTopErrorCell(true); if (currentDocumentsType != null) { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + actionBar.setTitle(LocaleController.getString("ActionBotDocumentRentalAgreement", R.string.ActionBotDocumentRentalAgreement)); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeBankStatement) { + actionBar.setTitle(LocaleController.getString("ActionBotDocumentBankStatement", R.string.ActionBotDocumentBankStatement)); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeUtilityBill) { + actionBar.setTitle(LocaleController.getString("ActionBotDocumentUtilityBill", R.string.ActionBotDocumentUtilityBill)); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassportRegistration) { + actionBar.setTitle(LocaleController.getString("ActionBotDocumentPassportRegistration", R.string.ActionBotDocumentPassportRegistration)); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + actionBar.setTitle(LocaleController.getString("ActionBotDocumentTemporaryRegistration", R.string.ActionBotDocumentTemporaryRegistration)); + } + headerCell = new HeaderCell(context); headerCell.setText(LocaleController.getString("PassportDocuments", R.string.PassportDocuments)); headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -2786,12 +3128,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter uploadDocumentCell = new TextSettingsCell(context); uploadDocumentCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); linearLayout2.addView(uploadDocumentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - uploadDocumentCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadingFileType = UPLOADING_TYPE_DOCUMENTS; - openAttachMenu(); - } + uploadDocumentCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_DOCUMENTS; + openAttachMenu(); }); bottomCell = new TextInfoPrivacyCell(context); @@ -2800,15 +3139,15 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (currentBotId != 0) { noAllDocumentsErrorText = LocaleController.getString("PassportAddAddressUploadInfo", R.string.PassportAddAddressUploadInfo); } else { - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { noAllDocumentsErrorText = LocaleController.getString("PassportAddAgreementInfo", R.string.PassportAddAgreementInfo); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeUtilityBill) { + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeUtilityBill) { noAllDocumentsErrorText = LocaleController.getString("PassportAddBillInfo", R.string.PassportAddBillInfo); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypePassportRegistration) { + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassportRegistration) { noAllDocumentsErrorText = LocaleController.getString("PassportAddPassportRegistrationInfo", R.string.PassportAddPassportRegistrationInfo); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { noAllDocumentsErrorText = LocaleController.getString("PassportAddTemporaryRegistrationInfo", R.string.PassportAddTemporaryRegistrationInfo); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeBankStatement) { + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeBankStatement) { noAllDocumentsErrorText = LocaleController.getString("PassportAddBankInfo", R.string.PassportAddBankInfo); } else { noAllDocumentsErrorText = ""; @@ -2829,6 +3168,63 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } bottomCell.setText(text); linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + if (currentDocumentsType.translation_required) { + headerCell = new HeaderCell(context); + headerCell.setText(LocaleController.getString("PassportTranslation", R.string.PassportTranslation)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + translationLayout = new LinearLayout(context); + translationLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout2.addView(translationLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + uploadTranslationCell = new TextSettingsCell(context); + uploadTranslationCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); + linearLayout2.addView(uploadTranslationCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + uploadTranslationCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_TRANSLATION; + openAttachMenu(); + }); + + bottomCellTranslation = new TextInfoPrivacyCell(context); + bottomCellTranslation.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + + if (currentBotId != 0) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationUploadInfo", R.string.PassportAddTranslationUploadInfo); + } else { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationAgreementInfo", R.string.PassportAddTranslationAgreementInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeUtilityBill) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationBillInfo", R.string.PassportAddTranslationBillInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassportRegistration) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationPassportRegistrationInfo", R.string.PassportAddTranslationPassportRegistrationInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationTemporaryRegistrationInfo", R.string.PassportAddTranslationTemporaryRegistrationInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeBankStatement) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationBankInfo", R.string.PassportAddTranslationBankInfo); + } else { + noAllTranslationErrorText = ""; + } + } + + text = noAllTranslationErrorText; + if (documentsErrors != null) { + String errorText; + if ((errorText = documentsErrors.get("translation_all")) != null) { + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(errorText); + stringBuilder.append("\n\n"); + stringBuilder.append(noAllTranslationErrorText); + text = stringBuilder; + stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)), 0, errorText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + errorsValues.put("translation_all", ""); + } + } + bottomCellTranslation.setText(text); + linearLayout2.addView(bottomCellTranslation, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + } else { + actionBar.setTitle(LocaleController.getString("PassportAddress", R.string.PassportAddress)); } headerCell = new HeaderCell(context); @@ -2894,7 +3290,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter linearLayout2.addView(extraBackgroundView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 6)); } - if (currentBotId == 0 && currentDocumentsType != null) { + if (documentOnly && currentDocumentsType != null) { container.setVisibility(View.GONE); if (extraBackgroundView != null) { extraBackgroundView.setVisibility(View.GONE); @@ -2914,25 +3310,19 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setCursorWidth(1.5f); inputFields[a].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); if (a == FIELD_COUNTRY) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - CountrySelectActivity fragment = new CountrySelectActivity(false); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - inputFields[FIELD_COUNTRY].setText(name); - currentCitizeship = shortName; - } - }); - presentFragment(fragment); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + CountrySelectActivity fragment = new CountrySelectActivity(false); + fragment.setCountrySelectActivityDelegate((name, shortName) -> { + inputFields[FIELD_COUNTRY].setText(name); + currentCitizeship = shortName; + }); + presentFragment(fragment); + } + return true; }); inputFields[a].setInputType(0); inputFields[a].setFocusable(false); @@ -2970,7 +3360,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter default: continue; } - setFieldValues(inputFields[a], key); + setFieldValues(currentValues, inputFields[a], key); if (a == FIELD_POSTCODE) { inputFields[a].addTextChangedListener(new TextWatcher() { @@ -3004,7 +3394,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (error) { field.setErrorText(LocaleController.getString("PassportUseLatinOnly", R.string.PassportUseLatinOnly)); } else { - checkFieldForError(field, key, s); + checkFieldForError(field, key, s, false); } } }); @@ -3025,7 +3415,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter @Override public void afterTextChanged(Editable s) { - checkFieldForError(field, key, s); + checkFieldForError(field, key, s, false); } }); } @@ -3035,113 +3425,104 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 64, Gravity.LEFT | Gravity.TOP, 17, 0, 17, 0)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - int num = (Integer) textView.getTag(); - num++; - if (num < inputFields.length) { - if (inputFields[num].isFocusable()) { - inputFields[num].requestFocus(); - } else { - inputFields[num].dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0)); - textView.clearFocus(); - AndroidUtilities.hideKeyboard(textView); - } + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + num++; + if (num < inputFields.length) { + if (inputFields[num].isFocusable()) { + inputFields[num].requestFocus(); + } else { + inputFields[num].dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0)); + textView.clearFocus(); + AndroidUtilities.hideKeyboard(textView); } - return true; } - return false; + return true; } + return false; }); } sectionCell = new ShadowSectionCell(context); linearLayout2.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - if (currentBotId == 0 && currentDocumentsType != null) { + if (documentOnly && currentDocumentsType != null) { headerCell.setVisibility(View.GONE); sectionCell.setVisibility(View.GONE); } - if ((currentBotId != 0 || currentDocumentsType == null) && currentTypeValue != null || currentDocumentsTypeValue != null) { + if ((currentBotId != 0 || currentDocumentsType == null) && currentTypeValue != null && !documentOnly || currentDocumentsTypeValue != null) { if (currentDocumentsTypeValue != null) { addDocumentViews(currentDocumentsTypeValue.files); + addTranslationDocumentViews(currentDocumentsTypeValue.translation); } sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); TextSettingsCell settingsCell1 = new TextSettingsCell(context); settingsCell1.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); settingsCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); - if (currentBotId == 0 && currentDocumentsType == null) { + if (currentDocumentsType == null) { settingsCell1.setText(LocaleController.getString("PassportDeleteInfo", R.string.PassportDeleteInfo), false); } else { settingsCell1.setText(LocaleController.getString("PassportDeleteDocument", R.string.PassportDeleteDocument), false); } linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - createDocumentDeleteAlert(); - } - }); + settingsCell1.setOnClickListener(v -> createDocumentDeleteAlert()); sectionCell = new ShadowSectionCell(context); sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); linearLayout2.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } else { sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - if (currentBotId == 0 && currentDocumentsType != null) { + if (documentOnly && currentDocumentsType != null) { bottomCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } } updateUploadText(UPLOADING_TYPE_DOCUMENTS); + updateUploadText(UPLOADING_TYPE_TRANSLATION); } private void createDocumentDeleteAlert() { final boolean checks[] = new boolean[]{true}; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + if (!documentOnly) { currentValues.clear(); - delegate.deleteValue(currentType, currentDocumentsType, checks[0], null, null); - finishFragment(); } + currentDocumentValues.clear(); + delegate.deleteValue(currentType, currentDocumentsType, availableDocumentTypes, checks[0], null, null); + finishFragment(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - if (currentBotId == 0 && currentDocumentsType == null && currentType instanceof TLRPC.TL_secureValueTypeAddress) { + if (documentOnly && currentDocumentsType == null && currentType.type instanceof TLRPC.TL_secureValueTypeAddress) { builder.setMessage(LocaleController.getString("PassportDeleteAddressAlert", R.string.PassportDeleteAddressAlert)); - } else if (currentBotId == 0 && currentDocumentsType == null && currentType instanceof TLRPC.TL_secureValueTypePersonalDetails) { + } else if (documentOnly && currentDocumentsType == null && currentType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { builder.setMessage(LocaleController.getString("PassportDeletePersonalAlert", R.string.PassportDeletePersonalAlert)); } else { builder.setMessage(LocaleController.getString("PassportDeleteDocumentAlert", R.string.PassportDeleteDocumentAlert)); } - if (currentBotId != 0 && currentDocumentsType != null) { + if (!documentOnly && currentDocumentsType != null) { FrameLayout frameLayout = new FrameLayout(getParentActivity()); CheckBoxCell cell = new CheckBoxCell(getParentActivity(), 1); cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - if (currentType instanceof TLRPC.TL_secureValueTypeAddress) { + if (currentType.type instanceof TLRPC.TL_secureValueTypeAddress) { cell.setText(LocaleController.getString("PassportDeleteDocumentAddress", R.string.PassportDeleteDocumentAddress), "", true, false); - } else if (currentType instanceof TLRPC.TL_secureValueTypePersonalDetails) { + } else if (currentType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { cell.setText(LocaleController.getString("PassportDeleteDocumentPersonal", R.string.PassportDeleteDocumentPersonal), "", true, false); } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!v.isEnabled()) { - return; - } - CheckBoxCell cell = (CheckBoxCell) v; - checks[0] = !checks[0]; - cell.setChecked(checks[0], true); + cell.setOnClickListener(v -> { + if (!v.isEnabled()) { + return; } + CheckBoxCell cell1 = (CheckBoxCell) v; + checks[0] = !checks[0]; + cell1.setChecked(checks[0], true); }); builder.setView(frameLayout); } @@ -3158,6 +3539,10 @@ public class PassportActivity extends BaseFragment implements NotificationCenter v.vibrate(200); } AndroidUtilities.shakeView(field, 2, 0); + scrollToField(field); + } + + private void scrollToField(View field) { while (field != null && linearLayout2.indexOfChild(field) < 0) { field = (View) field.getParent(); } @@ -3177,7 +3562,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return ""; } - private void checkFieldForError(EditTextBoldCursor field, String key, Editable s) { + private void checkFieldForError(EditTextBoldCursor field, String key, Editable s, boolean document) { String value; if (errorsValues != null && (value = errorsValues.get(key)) != null) { if (TextUtils.equals(value, s)) { @@ -3192,10 +3577,19 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } else { field.setErrorText(null); } + String errorKey = document ? "error_document_all" : "error_all"; + if (errorsValues != null && errorsValues.containsKey(errorKey)) { + errorsValues.remove(errorKey); + checkTopErrorCell(false); + } } private boolean checkFieldsForError() { if (currentDocumentsType != null) { + if (errorsValues.containsKey("error_all") || errorsValues.containsKey("error_document_all")) { + onFieldError(topErrorCell); + return true; + } if (uploadDocumentCell != null) { if (documents.isEmpty()) { onFieldError(uploadDocumentCell); @@ -3211,7 +3605,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } } - if (errorsValues.containsKey("files_all")) { + if (errorsValues.containsKey("files_all") || errorsValues.containsKey("translation_all")) { onFieldError(bottomCell); return true; } @@ -3227,7 +3621,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } } - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeIdentityCard || currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense) { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeIdentityCard || currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { if (uploadReverseCell != null) { if (reverseDocument == null) { onFieldError(uploadReverseCell); @@ -3241,7 +3635,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } } - if (uploadSelfieCell != null) { + if (uploadSelfieCell != null && currentBotId != 0) { if (selfieDocument == null) { onFieldError(uploadSelfieCell); return true; @@ -3253,128 +3647,179 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } } - } - for (int a = 0; a < inputFields.length; a++) { - boolean error = false; - if (inputFields[a].hasErrorText()) { - error = true; - } - if (!errorsValues.isEmpty()) { - String key; - if (currentType instanceof TLRPC.TL_secureValueTypePersonalDetails) { - switch (a) { - case FIELD_NAME: - key = "first_name"; - break; - case FIELD_SURNAME: - key = "last_name"; - break; - case FIELD_BIRTHDAY: - key = "birth_date"; - break; - case FIELD_GENDER: - key = "gender"; - break; - case FIELD_CITIZENSHIP: - key = "country_code"; - break; - case FIELD_RESIDENCE: - key = "residence_country_code"; - break; - case FIELD_CARDNUMBER: - key = "document_no"; - break; - case FIELD_EXPIRE: - key = "expiry_date"; - break; - default: - key = null; - break; - } - } else if (currentType instanceof TLRPC.TL_secureValueTypeAddress) { - switch (a) { - case FIELD_STREET1: - key = "street_line1"; - break; - case FIELD_STREET2: - key = "street_line2"; - break; - case FIELD_CITY: - key = "city"; - break; - case FIELD_STATE: - key = "state"; - break; - case FIELD_COUNTRY: - key = "country_code"; - break; - case FIELD_POSTCODE: - key = "post_code"; - break; - default: - key = null; - break; - } + if (uploadTranslationCell != null && currentBotId != 0) { + if (translationDocuments.isEmpty()) { + onFieldError(uploadTranslationCell); + return true; } else { - key = null; - } - if (key != null) { - String value = errorsValues.get(key); - if (!TextUtils.isEmpty(value)) { - if (value.equals(inputFields[a].getText().toString())) { - error = true; + for (int a = 0, size = translationDocuments.size(); a < size; a++) { + SecureDocument document = translationDocuments.get(a); + String key = "translation" + getDocumentHash(document); + if (key != null && errorsValues.containsKey(key)) { + onFieldError(documentsCells.get(document)); + return true; } } } } - if (currentBotId == 0) { - if (currentDocumentsType != null && a < FIELD_CARDNUMBER) { - continue; - } + } + for (int i = 0; i < 2; i++) { + EditTextBoldCursor[] fields; + if (i == 0) { + fields = inputFields; + } else { + fields = nativeInfoCell != null && nativeInfoCell.getVisibility() == View.VISIBLE ? inputExtraFields : null; } - if (!error) { - int len = inputFields[a].length(); - if (currentActivityType == TYPE_IDENTITY) { - if (a == FIELD_EXPIRE) { - continue; - } else if (a == FIELD_NAME || a == FIELD_SURNAME) { - if (len > 255) { - error = true; + if (fields == null) { + continue; + } + for (int a = 0; a < fields.length; a++) { + boolean error = false; + if (fields[a].hasErrorText()) { + error = true; + } + if (!errorsValues.isEmpty()) { + String key; + if (currentType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (i == 0) { + switch (a) { + case FIELD_NAME: + key = "first_name"; + break; + case FIELD_MIDNAME: + key = "middle_name"; + break; + case FIELD_SURNAME: + key = "last_name"; + break; + case FIELD_BIRTHDAY: + key = "birth_date"; + break; + case FIELD_GENDER: + key = "gender"; + break; + case FIELD_CITIZENSHIP: + key = "country_code"; + break; + case FIELD_RESIDENCE: + key = "residence_country_code"; + break; + case FIELD_CARDNUMBER: + key = "document_no"; + break; + case FIELD_EXPIRE: + key = "expiry_date"; + break; + default: + key = null; + break; + } + } else { + switch (a) { + case FIELD_NATIVE_NAME: + key = "first_name_native"; + break; + case FIELD_NATIVE_MIDNAME: + key = "middle_name_native"; + break; + case FIELD_NATIVE_SURNAME: + key = "last_name_native"; + break; + default: + key = null; + break; + } } - } else if (a == FIELD_CARDNUMBER) { - if (len > 24) { - error = true; + } else if (currentType.type instanceof TLRPC.TL_secureValueTypeAddress) { + switch (a) { + case FIELD_STREET1: + key = "street_line1"; + break; + case FIELD_STREET2: + key = "street_line2"; + break; + case FIELD_CITY: + key = "city"; + break; + case FIELD_STATE: + key = "state"; + break; + case FIELD_COUNTRY: + key = "country_code"; + break; + case FIELD_POSTCODE: + key = "post_code"; + break; + default: + key = null; + break; + } + } else { + key = null; + } + if (key != null) { + String value = errorsValues.get(key); + if (!TextUtils.isEmpty(value)) { + if (value.equals(fields[a].getText().toString())) { + error = true; + } } } - } else if (currentActivityType == TYPE_ADDRESS) { - if (a == FIELD_STREET2) { + } + if (documentOnly) { + if (currentDocumentsType != null && a < FIELD_CARDNUMBER) { continue; - } else if (a == FIELD_CITY) { - if (len < 2) { - error = true; + } + } + if (!error) { + int len = fields[a].length(); + boolean allowZeroLength = false; + if (currentActivityType == TYPE_IDENTITY) { + if (a == FIELD_EXPIRE) { + continue; + } else if (i == 0 && (a == FIELD_NAME || a == FIELD_SURNAME || a == FIELD_MIDNAME) || + i == 1 && (a == FIELD_NATIVE_NAME || a == FIELD_NATIVE_MIDNAME || a == FIELD_NATIVE_SURNAME)) { + if (len > 255) { + error = true; + } + if (i == 0 && a == FIELD_MIDNAME || i == 1 && a == FIELD_NATIVE_MIDNAME) { + allowZeroLength = true; + } + } else if (a == FIELD_CARDNUMBER) { + if (len > 24) { + error = true; + } } - } else if (a == FIELD_STATE) { - if ("US".equals(currentCitizeship)) { + } else if (currentActivityType == TYPE_ADDRESS) { + if (a == FIELD_STREET2) { + continue; + } else if (a == FIELD_CITY) { if (len < 2) { error = true; } - } else { - continue; - } - } else if (a == FIELD_POSTCODE) { - if (len < 2 || len > 10) { - error = true; + } else if (a == FIELD_STATE) { + if ("US".equals(currentCitizeship)) { + if (len < 2) { + error = true; + } + } else { + continue; + } + } else if (a == FIELD_POSTCODE) { + if (len < 2 || len > 10) { + error = true; + } } } + if (!error && !allowZeroLength && len == 0) { + error = true; + } } - if (!error && len == 0) { - error = true; + if (error) { + onFieldError(fields[a]); + return true; } } - if (error) { - onFieldError(inputFields[a]); - return true; - } } return false; } @@ -3393,9 +3838,15 @@ public class PassportActivity extends BaseFragment implements NotificationCenter FileLog.e(e); } + topErrorCell = new TextInfoPrivacyCell(context); + topErrorCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + topErrorCell.setPadding(0, AndroidUtilities.dp(7), 0, 0); + linearLayout2.addView(topErrorCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + checkTopErrorCell(true); + if (currentDocumentsType != null) { headerCell = new HeaderCell(context); - if (currentBotId == 0) { + if (documentOnly) { headerCell.setText(LocaleController.getString("PassportDocuments", R.string.PassportDocuments)); } else { headerCell.setText(LocaleController.getString("PassportRequiredDocuments", R.string.PassportRequiredDocuments)); @@ -3410,45 +3861,38 @@ public class PassportActivity extends BaseFragment implements NotificationCenter uploadFrontCell = new TextDetailSettingsCell(context); uploadFrontCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); linearLayout2.addView(uploadFrontCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - uploadFrontCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadingFileType = UPLOADING_TYPE_FRONT; - openAttachMenu(); - } + uploadFrontCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_FRONT; + openAttachMenu(); }); reverseLayout = new LinearLayout(context); reverseLayout.setOrientation(LinearLayout.VERTICAL); linearLayout2.addView(reverseLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + boolean divider = currentDocumentsType.selfie_required; + uploadReverseCell = new TextDetailSettingsCell(context); uploadReverseCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); - uploadReverseCell.setTextAndValue(LocaleController.getString("PassportReverseSide", R.string.PassportReverseSide), LocaleController.getString("PassportReverseSideInfo", R.string.PassportReverseSideInfo), currentForm.selfie_required); + uploadReverseCell.setTextAndValue(LocaleController.getString("PassportReverseSide", R.string.PassportReverseSide), LocaleController.getString("PassportReverseSideInfo", R.string.PassportReverseSideInfo), divider); linearLayout2.addView(uploadReverseCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - uploadReverseCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadingFileType = UPLOADING_TYPE_REVERSE; - openAttachMenu(); - } + uploadReverseCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_REVERSE; + openAttachMenu(); }); - if (currentForm.selfie_required) { + if (currentDocumentsType.selfie_required) { selfieLayout = new LinearLayout(context); selfieLayout.setOrientation(LinearLayout.VERTICAL); linearLayout2.addView(selfieLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); uploadSelfieCell = new TextDetailSettingsCell(context); uploadSelfieCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); - uploadSelfieCell.setTextAndValue(LocaleController.getString("PassportSelfie", R.string.PassportSelfie), LocaleController.getString("PassportSelfieInfo", R.string.PassportSelfieInfo), false); + uploadSelfieCell.setTextAndValue(LocaleController.getString("PassportSelfie", R.string.PassportSelfie), LocaleController.getString("PassportSelfieInfo", R.string.PassportSelfieInfo), currentType.translation_required); linearLayout2.addView(uploadSelfieCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - uploadSelfieCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadingFileType = UPLOADING_TYPE_SELFIE; - openAttachMenu(); - } + uploadSelfieCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_SELFIE; + openAttachMenu(); }); } @@ -3456,61 +3900,111 @@ public class PassportActivity extends BaseFragment implements NotificationCenter bottomCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); bottomCell.setText(LocaleController.getString("PassportPersonalUploadInfo", R.string.PassportPersonalUploadInfo)); linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + if (currentDocumentsType.translation_required) { + headerCell = new HeaderCell(context); + headerCell.setText(LocaleController.getString("PassportTranslation", R.string.PassportTranslation)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + translationLayout = new LinearLayout(context); + translationLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout2.addView(translationLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + uploadTranslationCell = new TextSettingsCell(context); + uploadTranslationCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); + linearLayout2.addView(uploadTranslationCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + uploadTranslationCell.setOnClickListener(v -> { + uploadingFileType = UPLOADING_TYPE_TRANSLATION; + openAttachMenu(); + }); + + bottomCellTranslation = new TextInfoPrivacyCell(context); + bottomCellTranslation.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + + if (currentBotId != 0) { + noAllTranslationErrorText = LocaleController.getString("PassportAddTranslationUploadInfo", R.string.PassportAddTranslationUploadInfo); + } else { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassport) { + noAllTranslationErrorText = LocaleController.getString("PassportAddPassportInfo", R.string.PassportAddPassportInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { + noAllTranslationErrorText = LocaleController.getString("PassportAddInternalPassportInfo", R.string.PassportAddInternalPassportInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + noAllTranslationErrorText = LocaleController.getString("PassportAddIdentityCardInfo", R.string.PassportAddIdentityCardInfo); + } else if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { + noAllTranslationErrorText = LocaleController.getString("PassportAddDriverLicenceInfo", R.string.PassportAddDriverLicenceInfo); + } else { + noAllTranslationErrorText = ""; + } + } + + CharSequence text = noAllTranslationErrorText; + if (documentsErrors != null) { + String errorText; + if ((errorText = documentsErrors.get("translation_all")) != null) { + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(errorText); + stringBuilder.append("\n\n"); + stringBuilder.append(noAllTranslationErrorText); + text = stringBuilder; + stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)), 0, errorText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + errorsValues.put("translation_all", ""); + } + } + bottomCellTranslation.setText(text); + linearLayout2.addView(bottomCellTranslation, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } } else if (Build.VERSION.SDK_INT >= 18) { scanDocumentCell = new TextSettingsCell(context); scanDocumentCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); scanDocumentCell.setText(LocaleController.getString("PassportScanPassport", R.string.PassportScanPassport), false); linearLayout2.addView(scanDocumentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - scanDocumentCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 22); - return; - } - MrzCameraActivity fragment = new MrzCameraActivity(); - fragment.setDelegate(new MrzCameraActivity.MrzCameraActivityDelegate() { - @Override - public void didFindMrzInfo(MrzRecognizer.Result result) { - if (!TextUtils.isEmpty(result.firstName)) { - inputFields[FIELD_NAME].setText(result.firstName); - } - if (!TextUtils.isEmpty(result.lastName)) { - inputFields[FIELD_SURNAME].setText(result.lastName); - } - if (result.gender != MrzRecognizer.Result.GENDER_UNKNOWN) { - switch (result.gender) { - case MrzRecognizer.Result.GENDER_MALE: - currentGender = "male"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); - break; - case MrzRecognizer.Result.GENDER_FEMALE: - currentGender = "female"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); - break; - } - } - if (!TextUtils.isEmpty(result.nationality)) { - currentCitizeship = result.nationality; - String country = languageMap.get(currentCitizeship); - if (country != null) { - inputFields[FIELD_CITIZENSHIP].setText(country); - } - } - if (!TextUtils.isEmpty(result.issuingCountry)) { - currentResidence = result.issuingCountry; - String country = languageMap.get(currentResidence); - if (country != null) { - inputFields[FIELD_RESIDENCE].setText(country); - } - } - if (result.birthDay > 0 && result.birthMonth > 0 && result.birthYear > 0) { - inputFields[FIELD_BIRTHDAY].setText(String.format(Locale.US, "%02d.%02d.%d", result.birthDay, result.birthMonth, result.birthYear)); - } - } - }); - presentFragment(fragment); + scanDocumentCell.setOnClickListener(v -> { + if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 22); + return; } + MrzCameraActivity fragment = new MrzCameraActivity(); + fragment.setDelegate(result -> { + if (!TextUtils.isEmpty(result.firstName)) { + inputFields[FIELD_NAME].setText(result.firstName); + } + if (!TextUtils.isEmpty(result.middleName)) { + inputFields[FIELD_MIDNAME].setText(result.middleName); + } + if (!TextUtils.isEmpty(result.lastName)) { + inputFields[FIELD_SURNAME].setText(result.lastName); + } + if (result.gender != MrzRecognizer.Result.GENDER_UNKNOWN) { + switch (result.gender) { + case MrzRecognizer.Result.GENDER_MALE: + currentGender = "male"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); + break; + case MrzRecognizer.Result.GENDER_FEMALE: + currentGender = "female"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); + break; + } + } + if (!TextUtils.isEmpty(result.nationality)) { + currentCitizeship = result.nationality; + String country = languageMap.get(currentCitizeship); + if (country != null) { + inputFields[FIELD_CITIZENSHIP].setText(country); + } + } + if (!TextUtils.isEmpty(result.issuingCountry)) { + currentResidence = result.issuingCountry; + String country = languageMap.get(currentResidence); + if (country != null) { + inputFields[FIELD_RESIDENCE].setText(country); + } + } + if (result.birthDay > 0 && result.birthMonth > 0 && result.birthYear > 0) { + inputFields[FIELD_BIRTHDAY].setText(String.format(Locale.US, "%02d.%02d.%d", result.birthDay, result.birthMonth, result.birthYear)); + } + }); + presentFragment(fragment); }); bottomCell = new TextInfoPrivacyCell(context); @@ -3520,7 +4014,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } headerCell = new HeaderCell(context); - headerCell.setText(LocaleController.getString("PassportPersonal", R.string.PassportPersonal)); + if (documentOnly) { + headerCell.setText(LocaleController.getString("PassportDocument", R.string.PassportDocument)); + } else { + headerCell.setText(LocaleController.getString("PassportPersonal", R.string.PassportPersonal)); + } headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); linearLayout2.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -3584,7 +4082,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter linearLayout2.addView(extraBackgroundView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 6)); } - if (currentBotId == 0 && currentDocumentsType != null && a < FIELD_CARDNUMBER) { + if (documentOnly && currentDocumentsType != null && a < FIELD_CARDNUMBER) { container.setVisibility(View.GONE); if (extraBackgroundView != null) { extraBackgroundView.setVisibility(View.GONE); @@ -3604,118 +4102,111 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setCursorWidth(1.5f); inputFields[a].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); if (a == FIELD_CITIZENSHIP || a == FIELD_RESIDENCE) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(final View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - CountrySelectActivity fragment = new CountrySelectActivity(false); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - int field = (Integer) v.getTag(); - final EditTextBoldCursor editText = inputFields[field]; - editText.setText(name); - if (field == FIELD_CITIZENSHIP) { - currentCitizeship = shortName; - } else { - currentResidence = shortName; - } - } - }); - presentFragment(fragment); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + CountrySelectActivity fragment = new CountrySelectActivity(false); + fragment.setCountrySelectActivityDelegate((name, shortName) -> { + int field12 = (Integer) v.getTag(); + final EditTextBoldCursor editText = inputFields[field12]; + if (field12 == FIELD_CITIZENSHIP) { + currentCitizeship = shortName; + } else { + currentResidence = shortName; + } + editText.setText(name); + }); + presentFragment(fragment); + } + return true; }); inputFields[a].setInputType(0); } else if (a == FIELD_BIRTHDAY || a == FIELD_EXPIRE) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(final View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - Calendar calendar = Calendar.getInstance(); - int year = calendar.get(Calendar.YEAR); - int monthOfYear = calendar.get(Calendar.MONTH); - int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); - try { - final EditTextBoldCursor field = (EditTextBoldCursor) v; - int num = (Integer) field.getTag(); - int minYear; - int maxYear; - String title; - if (num == FIELD_EXPIRE) { - title = LocaleController.getString("PassportSelectExpiredDate", R.string.PassportSelectExpiredDate); - minYear = 0; - maxYear = 20; - } else { - title = LocaleController.getString("PassportSelectBithdayDate", R.string.PassportSelectBithdayDate); - minYear = -120; - maxYear = 0; - } - AlertDialog.Builder builder = AlertsCreator.createDatePickerDialog(context, minYear, maxYear, title, num == FIELD_EXPIRE, new AlertsCreator.DatePickerDelegate() { - @Override - public void didSelectDate(int year, int month, int dayOfMonth) { - currentExpireDate[0] = year; - currentExpireDate[1] = month + 1; - currentExpireDate[2] = dayOfMonth; - field.setText(String.format(Locale.US, "%02d.%02d.%d", dayOfMonth, month + 1, year)); - } - }); - if (num == FIELD_EXPIRE) { - builder.setNegativeButton(LocaleController.getString("PassportSelectNotExpire", R.string.PassportSelectNotExpire), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - currentExpireDate[0] = currentExpireDate[1] = currentExpireDate[2] = 0; - field.setText(LocaleController.getString("PassportNoExpireDate", R.string.PassportNoExpireDate)); - } - }); - } - showDialog(builder.create()); - } catch (Exception e) { - FileLog.e(e); - } - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + int monthOfYear = calendar.get(Calendar.MONTH); + int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); + try { + final EditTextBoldCursor field1 = (EditTextBoldCursor) v; + int num = (Integer) field1.getTag(); + int minYear; + int maxYear; + int currentYearDiff; + String title; + if (num == FIELD_EXPIRE) { + title = LocaleController.getString("PassportSelectExpiredDate", R.string.PassportSelectExpiredDate); + minYear = 0; + maxYear = 20; + currentYearDiff = 0; + } else { + title = LocaleController.getString("PassportSelectBithdayDate", R.string.PassportSelectBithdayDate); + minYear = -120; + maxYear = 0; + currentYearDiff = -18; + } + int selectedDay = -1; + int selectedMonth = -1; + int selectedYear = -1; + String args[] = field1.getText().toString().split("\\."); + if (args.length == 3) { + selectedDay = Utilities.parseInt(args[0]); + selectedMonth = Utilities.parseInt(args[1]); + selectedYear = Utilities.parseInt(args[2]); + } + AlertDialog.Builder builder = AlertsCreator.createDatePickerDialog(context, minYear, maxYear, currentYearDiff, selectedDay, selectedMonth, selectedYear, title, num == FIELD_EXPIRE, (year1, month, dayOfMonth1) -> { + if (num == FIELD_EXPIRE) { + currentExpireDate[0] = year1; + currentExpireDate[1] = month + 1; + currentExpireDate[2] = dayOfMonth1; + } + field1.setText(String.format(Locale.US, "%02d.%02d.%d", dayOfMonth1, month + 1, year1)); + }); + if (num == FIELD_EXPIRE) { + builder.setNegativeButton(LocaleController.getString("PassportSelectNotExpire", R.string.PassportSelectNotExpire), (dialog, which) -> { + currentExpireDate[0] = currentExpireDate[1] = currentExpireDate[2] = 0; + field1.setText(LocaleController.getString("PassportNoExpireDate", R.string.PassportNoExpireDate)); + }); + } + showDialog(builder.create()); + } catch (Exception e) { + FileLog.e(e); + } + } + return true; }); inputFields[a].setInputType(0); inputFields[a].setFocusable(false); } else if (a == FIELD_GENDER) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(final View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("PassportSelectGender", R.string.PassportSelectGender)); - builder.setItems(new CharSequence[]{ - LocaleController.getString("PassportMale", R.string.PassportMale), - LocaleController.getString("PassportFemale", R.string.PassportFemale) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - currentGender = "male"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); - } else if (i == 1) { - currentGender = "female"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); - } - } - }); - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("PassportSelectGender", R.string.PassportSelectGender)); + builder.setItems(new CharSequence[]{ + LocaleController.getString("PassportMale", R.string.PassportMale), + LocaleController.getString("PassportFemale", R.string.PassportFemale) + }, (dialogInterface, i) -> { + if (i == 0) { + currentGender = "male"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); + } else if (i == 1) { + currentGender = "female"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); + } + }); + builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + return true; }); inputFields[a].setInputType(0); inputFields[a].setFocusable(false); @@ -3725,45 +4216,71 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } String value; final String key; + HashMap values; switch (a) { case FIELD_NAME: - inputFields[a].setHintText(LocaleController.getString("PassportName", R.string.PassportName)); + if (currentType.native_names) { + inputFields[a].setHintText(LocaleController.getString("PassportNameLatin", R.string.PassportNameLatin)); + } else { + inputFields[a].setHintText(LocaleController.getString("PassportName", R.string.PassportName)); + } key = "first_name"; + values = currentValues; + break; + case FIELD_MIDNAME: + if (currentType.native_names) { + inputFields[a].setHintText(LocaleController.getString("PassportMidnameLatin", R.string.PassportMidnameLatin)); + } else { + inputFields[a].setHintText(LocaleController.getString("PassportMidname", R.string.PassportMidname)); + } + key = "middle_name"; + values = currentValues; break; case FIELD_SURNAME: - inputFields[a].setHintText(LocaleController.getString("PassportSurname", R.string.PassportSurname)); + if (currentType.native_names) { + inputFields[a].setHintText(LocaleController.getString("PassportSurnameLatin", R.string.PassportSurnameLatin)); + } else { + inputFields[a].setHintText(LocaleController.getString("PassportSurname", R.string.PassportSurname)); + } key = "last_name"; + values = currentValues; break; case FIELD_BIRTHDAY: inputFields[a].setHintText(LocaleController.getString("PassportBirthdate", R.string.PassportBirthdate)); key = "birth_date"; + values = currentValues; break; case FIELD_GENDER: inputFields[a].setHintText(LocaleController.getString("PassportGender", R.string.PassportGender)); key = "gender"; + values = currentValues; break; case FIELD_CITIZENSHIP: inputFields[a].setHintText(LocaleController.getString("PassportCitizenship", R.string.PassportCitizenship)); key = "country_code"; + values = currentValues; break; case FIELD_RESIDENCE: inputFields[a].setHintText(LocaleController.getString("PassportResidence", R.string.PassportResidence)); key = "residence_country_code"; + values = currentValues; break; case FIELD_CARDNUMBER: inputFields[a].setHintText(LocaleController.getString("PassportDocumentNumber", R.string.PassportDocumentNumber)); key = "document_no"; + values = currentDocumentValues; break; case FIELD_EXPIRE: inputFields[a].setHintText(LocaleController.getString("PassportExpired", R.string.PassportExpired)); key = "expiry_date"; + values = currentDocumentValues; break; default: continue; } - setFieldValues(inputFields[a], key); + setFieldValues(values, inputFields[a], key); inputFields[a].setSelection(inputFields[a].length()); - if (a == FIELD_NAME || a == FIELD_SURNAME) { + if (a == FIELD_NAME || a == FIELD_SURNAME || a == FIELD_MIDNAME) { inputFields[a].addTextChangedListener(new TextWatcher() { private boolean ignore; @@ -3783,7 +4300,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (ignore) { return; } - ignore = true; + int num = (Integer) field.getTag(); boolean error = false; for (int a = 0; a < s.length(); a++) { char ch = s.charAt(a); @@ -3792,11 +4309,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter break; } } - ignore = false; - if (error) { + if (error && !allowNonLatinName) { field.setErrorText(LocaleController.getString("PassportUseLatinOnly", R.string.PassportUseLatinOnly)); } else { - checkFieldForError(field, key, s); + nonLatinNames[num] = error; + checkFieldForError(field, key, s, false); } } }); @@ -3814,7 +4331,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter @Override public void afterTextChanged(Editable s) { - checkFieldForError(field, key, s); + checkFieldForError(field, key, s, values == currentDocumentValues); + int field12 = (Integer) field.getTag(); + final EditTextBoldCursor editText = inputFields[field12]; + if (field12 == FIELD_RESIDENCE) { + checkNativeFields(true); + } } }); } @@ -3823,32 +4345,178 @@ public class PassportActivity extends BaseFragment implements NotificationCenter inputFields[a].setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, 0, 17, 0)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - int num = (Integer) textView.getTag(); - num++; - if (num < inputFields.length) { - if (inputFields[num].isFocusable()) { - inputFields[num].requestFocus(); - } else { - inputFields[num].dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0)); - textView.clearFocus(); - AndroidUtilities.hideKeyboard(textView); - } + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + num++; + if (num < inputFields.length) { + if (inputFields[num].isFocusable()) { + inputFields[num].requestFocus(); + } else { + inputFields[num].dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0)); + textView.clearFocus(); + AndroidUtilities.hideKeyboard(textView); } - return true; } - return false; + return true; } + return false; }); } - sectionCell = new ShadowSectionCell(context); - linearLayout2.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + sectionCell2 = new ShadowSectionCell(context); + linearLayout2.addView(sectionCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - if ((currentBotId != 0 || currentDocumentsType == null) && currentTypeValue != null || currentDocumentsTypeValue != null) { + headerCell = new HeaderCell(context); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + inputExtraFields = new EditTextBoldCursor[FIELD_NATIVE_COUNT]; + for (int a = 0; a < FIELD_NATIVE_COUNT; a++) { + final EditTextBoldCursor field = new EditTextBoldCursor(context); + inputExtraFields[a] = field; + + ViewGroup container = new FrameLayout(context) { + + private StaticLayout errorLayout; + private float offsetX; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(34); + errorLayout = field.getErrorLayout(width); + if (errorLayout != null) { + int lineCount = errorLayout.getLineCount(); + if (lineCount > 1) { + int height = AndroidUtilities.dp(64) + (errorLayout.getLineBottom(lineCount - 1) - errorLayout.getLineBottom(0)); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + } + if (LocaleController.isRTL) { + float maxW = 0; + for (int a = 0; a < lineCount; a++) { + float l = errorLayout.getLineLeft(a); + if (l != 0) { + offsetX = 0; + break; + } + maxW = Math.max(maxW, errorLayout.getLineWidth(a)); + if (a == lineCount - 1) { + offsetX = width - maxW; + } + } + } + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onDraw(Canvas canvas) { + if (errorLayout != null) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(17) + offsetX, field.getLineY() + AndroidUtilities.dp(3)); + errorLayout.draw(canvas); + canvas.restore(); + } + } + }; + container.setWillNotDraw(false); + linearLayout2.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64)); + container.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + + if (a == FIELD_NATIVE_COUNT - 1) { + extraBackgroundView2 = new View(context); + extraBackgroundView2.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + linearLayout2.addView(extraBackgroundView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 6)); + } + + inputExtraFields[a].setTag(a); + inputExtraFields[a].setSupportRtlHint(true); + inputExtraFields[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + inputExtraFields[a].setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); + inputExtraFields[a].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + inputExtraFields[a].setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader)); + inputExtraFields[a].setTransformHintToHeader(true); + inputExtraFields[a].setBackgroundDrawable(null); + inputExtraFields[a].setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + inputExtraFields[a].setCursorSize(AndroidUtilities.dp(20)); + inputExtraFields[a].setCursorWidth(1.5f); + inputExtraFields[a].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); + inputExtraFields[a].setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + inputExtraFields[a].setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); + + String value; + final String key; + HashMap values; + switch (a) { + case FIELD_NATIVE_NAME: + key = "first_name_native"; + values = currentValues; + break; + case FIELD_NATIVE_MIDNAME: + key = "middle_name_native"; + values = currentValues; + break; + case FIELD_NATIVE_SURNAME: + key = "last_name_native"; + values = currentValues; + break; + default: + continue; + } + setFieldValues(values, inputExtraFields[a], key); + inputExtraFields[a].setSelection(inputExtraFields[a].length()); + if (a == FIELD_NATIVE_NAME || a == FIELD_NATIVE_SURNAME || a == FIELD_NATIVE_MIDNAME) { + inputExtraFields[a].addTextChangedListener(new TextWatcher() { + + private boolean ignore; + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (ignore) { + return; + } + checkFieldForError(field, key, s, false); + } + }); + } + + inputExtraFields[a].setPadding(0, 0, 0, 0); + inputExtraFields[a].setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + container.addView(inputExtraFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, 0, 17, 0)); + + inputExtraFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + num++; + if (num < inputExtraFields.length) { + if (inputExtraFields[num].isFocusable()) { + inputExtraFields[num].requestFocus(); + } else { + inputExtraFields[num].dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0)); + textView.clearFocus(); + AndroidUtilities.hideKeyboard(textView); + } + } + return true; + } + return false; + }); + } + + nativeInfoCell = new TextInfoPrivacyCell(context); + linearLayout2.addView(nativeInfoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + if ((currentBotId != 0 || currentDocumentsType == null) && currentTypeValue != null && !documentOnly || currentDocumentsTypeValue != null) { if (currentDocumentsTypeValue != null) { addDocumentViews(currentDocumentsTypeValue.files); if (currentDocumentsTypeValue.front_side instanceof TLRPC.TL_secureFile) { @@ -3860,49 +4528,43 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (currentDocumentsTypeValue.selfie instanceof TLRPC.TL_secureFile) { addDocumentViewInternal((TLRPC.TL_secureFile) currentDocumentsTypeValue.selfie, UPLOADING_TYPE_SELFIE); } + addTranslationDocumentViews(currentDocumentsTypeValue.translation); } - sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); TextSettingsCell settingsCell1 = new TextSettingsCell(context); settingsCell1.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); settingsCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); - if (currentBotId == 0 && currentDocumentsType == null) { + if (currentDocumentsType == null) { settingsCell1.setText(LocaleController.getString("PassportDeleteInfo", R.string.PassportDeleteInfo), false); } else { settingsCell1.setText(LocaleController.getString("PassportDeleteDocument", R.string.PassportDeleteDocument), false); } linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - createDocumentDeleteAlert(); - } - }); + settingsCell1.setOnClickListener(v -> createDocumentDeleteAlert()); + + nativeInfoCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); sectionCell = new ShadowSectionCell(context); sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); linearLayout2.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } else { - sectionCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + nativeInfoCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } + updateInterfaceStringsForDocumentType(); + checkNativeFields(false); } private void updateInterfaceStringsForDocumentType() { - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentIdentityCard", R.string.ActionBotDocumentIdentityCard)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypePassport) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentPassport", R.string.ActionBotDocumentPassport)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeInternalPassport) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentInternalPassport", R.string.ActionBotDocumentInternalPassport)); - } else if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense) { - actionBar.setTitle(LocaleController.getString("ActionBotDocumentDriverLicence", R.string.ActionBotDocumentDriverLicence)); + if (currentDocumentsType != null) { + actionBar.setTitle(getTextForType(currentDocumentsType.type)); } else { actionBar.setTitle(LocaleController.getString("PassportPersonal", R.string.PassportPersonal)); } updateUploadText(UPLOADING_TYPE_FRONT); updateUploadText(UPLOADING_TYPE_REVERSE); updateUploadText(UPLOADING_TYPE_SELFIE); + updateUploadText(UPLOADING_TYPE_TRANSLATION); } private void updateUploadText(int type) { @@ -3920,12 +4582,24 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return; } uploadSelfieCell.setVisibility(selfieDocument != null ? View.GONE : View.VISIBLE); + } else if (type == UPLOADING_TYPE_TRANSLATION) { + if (uploadTranslationCell == null) { + return; + } + if (translationDocuments.size() >= 1) { + uploadTranslationCell.setText(LocaleController.getString("PassportUploadAdditinalDocument", R.string.PassportUploadAdditinalDocument), false); + } else { + uploadTranslationCell.setText(LocaleController.getString("PassportUploadDocument", R.string.PassportUploadDocument), false); + } } else if (type == UPLOADING_TYPE_FRONT) { if (uploadFrontCell == null) { return; } - boolean divider = currentForm.selfie_required || currentDocumentsType instanceof TLRPC.TL_secureValueTypeIdentityCard || currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense; - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypePassport || currentDocumentsType instanceof TLRPC.TL_secureValueTypeInternalPassport) { + boolean divider = currentDocumentsType != null && ( + currentDocumentsType.selfie_required || + currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeIdentityCard || + currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense); + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassport || currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { uploadFrontCell.setTextAndValue(LocaleController.getString("PassportMainPage", R.string.PassportMainPage), LocaleController.getString("PassportMainPageInfo", R.string.PassportMainPageInfo), divider); } else { uploadFrontCell.setTextAndValue(LocaleController.getString("PassportFrontSide", R.string.PassportFrontSide), LocaleController.getString("PassportFrontSideInfo", R.string.PassportFrontSideInfo), divider); @@ -3935,7 +4609,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (uploadReverseCell == null) { return; } - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypeIdentityCard || currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense) { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeIdentityCard || currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { reverseLayout.setVisibility(View.VISIBLE); uploadReverseCell.setVisibility(reverseDocument != null ? View.GONE : View.VISIBLE); } else { @@ -3945,6 +4619,42 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } + private void checkTopErrorCell(boolean init) { + if (topErrorCell == null) { + return; + } + SpannableStringBuilder stringBuilder = null; + if (fieldsErrors != null && (init || errorsValues.containsKey("error_all"))) { + String errorText = fieldsErrors.get("error_all"); + if (errorText != null) { + stringBuilder = new SpannableStringBuilder(errorText); + if (init) { + errorsValues.put("error_all", ""); + } + } + } + if (documentsErrors != null && (init || errorsValues.containsKey("error_document_all"))) { + String errorText = documentsErrors.get("error_all"); + if (errorText != null) { + if (stringBuilder == null) { + stringBuilder = new SpannableStringBuilder(errorText); + } else { + stringBuilder.append("\n\n").append(errorText); + } + if (init) { + errorsValues.put("error_document_all", ""); + } + } + } + if (stringBuilder != null) { + stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)), 0, stringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + topErrorCell.setText(stringBuilder); + topErrorCell.setVisibility(View.VISIBLE); + } else if (topErrorCell.getVisibility() != View.GONE) { + topErrorCell.setVisibility(View.GONE); + } + } + private void addDocumentViewInternal(TLRPC.TL_secureFile f, int uploadingType) { SecureDocumentKey secureDocumentKey = getSecureDocumentKey(f.secret, f.file_hash); SecureDocument secureDocument = new SecureDocument(secureDocumentKey, f, null, null, null); @@ -3961,9 +4671,19 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - private void setFieldValues(EditTextBoldCursor editText, String key) { + private void addTranslationDocumentViews(ArrayList files) { + translationDocuments.clear(); + for (int a = 0, size = files.size(); a < size; a++) { + TLRPC.SecureFile secureFile = files.get(a); + if (secureFile instanceof TLRPC.TL_secureFile) { + addDocumentViewInternal((TLRPC.TL_secureFile) secureFile, UPLOADING_TYPE_TRANSLATION); + } + } + } + + private void setFieldValues(HashMap values, EditTextBoldCursor editText, String key) { String value; - if ((value = currentValues.get(key)) != null) { + if ((value = values.get(key)) != null) { switch (key) { case "country_code": { currentCitizeship = value; @@ -4027,6 +4747,11 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (selfieLayout == null) { return; } + } else if (type == UPLOADING_TYPE_TRANSLATION) { + translationDocuments.add(document); + if (translationLayout == null) { + return; + } } else if (type == UPLOADING_TYPE_FRONT) { frontDocument = document; if (frontLayout == null) { @@ -4060,8 +4785,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter text = LocaleController.getString("PassportSelfie", R.string.PassportSelfie); selfieLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); key = "selfie" + hash; + } else if (type == UPLOADING_TYPE_TRANSLATION) { + text = LocaleController.getString("AttachPhoto", R.string.AttachPhoto); + translationLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + key = "translation" + hash; } else if (type == UPLOADING_TYPE_FRONT) { - if (currentDocumentsType instanceof TLRPC.TL_secureValueTypePassport || currentDocumentsType instanceof TLRPC.TL_secureValueTypeInternalPassport) { + if (currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassport || currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { text = LocaleController.getString("PassportMainPage", R.string.PassportMainPage); } else { text = LocaleController.getString("PassportFrontSide", R.string.PassportFrontSide); @@ -4086,81 +4815,77 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } cell.setTextAndValueAndImage(text, value, document); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadingFileType = type; - if (type == UPLOADING_TYPE_SELFIE) { - currentPhotoViewerLayout = selfieLayout; - } else if (type == UPLOADING_TYPE_FRONT) { - currentPhotoViewerLayout = frontLayout; - } else if (type == UPLOADING_TYPE_REVERSE) { - currentPhotoViewerLayout = reverseLayout; - } else { - currentPhotoViewerLayout = documentsLayout; - } - SecureDocument document = (SecureDocument) v.getTag(); - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - if (type == UPLOADING_TYPE_DOCUMENTS) { - PhotoViewer.getInstance().openPhoto(documents, documents.indexOf(document), provider); - } else { - ArrayList arrayList = new ArrayList<>(); - arrayList.add(document); - PhotoViewer.getInstance().openPhoto(arrayList, 0, provider); - } + cell.setOnClickListener(v -> { + uploadingFileType = type; + if (type == UPLOADING_TYPE_SELFIE) { + currentPhotoViewerLayout = selfieLayout; + } else if (type == UPLOADING_TYPE_TRANSLATION) { + currentPhotoViewerLayout = translationLayout; + } else if (type == UPLOADING_TYPE_FRONT) { + currentPhotoViewerLayout = frontLayout; + } else if (type == UPLOADING_TYPE_REVERSE) { + currentPhotoViewerLayout = reverseLayout; + } else { + currentPhotoViewerLayout = documentsLayout; + } + SecureDocument document1 = (SecureDocument) v.getTag(); + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + if (type == UPLOADING_TYPE_DOCUMENTS) { + PhotoViewer.getInstance().openPhoto(documents, documents.indexOf(document1), provider); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(document1); + PhotoViewer.getInstance().openPhoto(arrayList, 0, provider); } }); - cell.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - if (type == UPLOADING_TYPE_SELFIE) { - builder.setMessage(LocaleController.getString("PassportDeleteSelfie", R.string.PassportDeleteSelfie)); - } else { - builder.setMessage(LocaleController.getString("PassportDeleteScan", R.string.PassportDeleteScan)); - } - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - documentsCells.remove(document); - if (type == UPLOADING_TYPE_SELFIE) { - selfieDocument = null; - selfieLayout.removeView(cell); - } else if (type == UPLOADING_TYPE_FRONT) { - frontDocument = null; - frontLayout.removeView(cell); - } else if (type == UPLOADING_TYPE_REVERSE) { - reverseDocument = null; - reverseLayout.removeView(cell); - } else { - documents.remove(document); - documentsLayout.removeView(cell); - } - - if (key != null) { - if (documentsErrors != null) { - documentsErrors.remove(key); - } - if (errorsValues != null) { - errorsValues.remove(key); - } - } - - updateUploadText(type); - if (document.path != null && uploadingDocuments.remove(document.path) != null) { - if (uploadingDocuments.isEmpty()) { - doneItem.setEnabled(true); - doneItem.setAlpha(1.0f); - } - FileLoader.getInstance(currentAccount).cancelUploadFile(document.path, false); - } - } - }); - showDialog(builder.create()); - return true; + cell.setOnLongClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + if (type == UPLOADING_TYPE_SELFIE) { + builder.setMessage(LocaleController.getString("PassportDeleteSelfie", R.string.PassportDeleteSelfie)); + } else { + builder.setMessage(LocaleController.getString("PassportDeleteScan", R.string.PassportDeleteScan)); } + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + documentsCells.remove(document); + if (type == UPLOADING_TYPE_SELFIE) { + selfieDocument = null; + selfieLayout.removeView(cell); + } else if (type == UPLOADING_TYPE_TRANSLATION) { + translationDocuments.remove(document); + translationLayout.removeView(cell); + } else if (type == UPLOADING_TYPE_FRONT) { + frontDocument = null; + frontLayout.removeView(cell); + } else if (type == UPLOADING_TYPE_REVERSE) { + reverseDocument = null; + reverseLayout.removeView(cell); + } else { + documents.remove(document); + documentsLayout.removeView(cell); + } + + if (key != null) { + if (documentsErrors != null) { + documentsErrors.remove(key); + } + if (errorsValues != null) { + errorsValues.remove(key); + } + } + + updateUploadText(type); + if (document.path != null && uploadingDocuments.remove(document.path) != null) { + if (uploadingDocuments.isEmpty()) { + doneItem.setEnabled(true); + doneItem.setAlpha(1.0f); + } + FileLoader.getInstance(currentAccount).cancelUploadFile(document.path, false); + } + }); + showDialog(builder.create()); + return true; }); } @@ -4195,27 +4920,68 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return ""; } - private void setTypeValue(TLRPC.SecureValueType type, String text, String json, TLRPC.SecureValueType documentType, String documentsJson) { - TextDetailSecureCell view = typesViews.get(type); + private TextDetailSecureCell getViewByType(TLRPC.TL_secureRequiredType requiredType) { + TextDetailSecureCell view = typesViews.get(requiredType); + if (view == null) { + requiredType = documentsToTypesLink.get(requiredType); + if (requiredType != null) { + view = typesViews.get(requiredType); + } + } + return view; + } + + private String getTextForType(TLRPC.SecureValueType type) { + if (type instanceof TLRPC.TL_secureValueTypePassport) { + return LocaleController.getString("ActionBotDocumentPassport", R.string.ActionBotDocumentPassport); + } else if (type instanceof TLRPC.TL_secureValueTypeDriverLicense) { + return LocaleController.getString("ActionBotDocumentDriverLicence", R.string.ActionBotDocumentDriverLicence); + } else if (type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + return LocaleController.getString("ActionBotDocumentIdentityCard", R.string.ActionBotDocumentIdentityCard); + } else if (type instanceof TLRPC.TL_secureValueTypeUtilityBill) { + return LocaleController.getString("ActionBotDocumentUtilityBill", R.string.ActionBotDocumentUtilityBill); + } else if (type instanceof TLRPC.TL_secureValueTypeBankStatement) { + return LocaleController.getString("ActionBotDocumentBankStatement", R.string.ActionBotDocumentBankStatement); + } else if (type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + return LocaleController.getString("ActionBotDocumentRentalAgreement", R.string.ActionBotDocumentRentalAgreement); + } else if (type instanceof TLRPC.TL_secureValueTypeInternalPassport) { + return LocaleController.getString("ActionBotDocumentInternalPassport", R.string.ActionBotDocumentInternalPassport); + } else if (type instanceof TLRPC.TL_secureValueTypePassportRegistration) { + return LocaleController.getString("ActionBotDocumentPassportRegistration", R.string.ActionBotDocumentPassportRegistration); + } else if (type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + return LocaleController.getString("ActionBotDocumentTemporaryRegistration", R.string.ActionBotDocumentTemporaryRegistration); + } else if (type instanceof TLRPC.TL_secureValueTypePhone) { + return LocaleController.getString("ActionBotDocumentPhone", R.string.ActionBotDocumentPhone); + } else if (type instanceof TLRPC.TL_secureValueTypeEmail) { + return LocaleController.getString("ActionBotDocumentEmail", R.string.ActionBotDocumentEmail); + } + return ""; + } + + private void setTypeValue(TLRPC.TL_secureRequiredType requiredType, String text, String json, TLRPC.TL_secureRequiredType documentRequiredType, String documentsJson, boolean documentOnly, int availableDocumentTypesCount) { + TextDetailSecureCell view = typesViews.get(requiredType); if (view == null) { if (currentActivityType == TYPE_MANAGE) { - ArrayList documentTypes = new ArrayList<>(); - if (documentType != null) { - documentTypes.add(documentType); + ArrayList documentTypes = new ArrayList<>(); + if (documentRequiredType != null) { + documentTypes.add(documentRequiredType); } View prev = linearLayout2.getChildAt(linearLayout2.getChildCount() - 6); if (prev instanceof TextDetailSecureCell) { ((TextDetailSecureCell) prev).setNeedDivider(true); } - view = addField(getParentActivity(), type, documentTypes, true); + view = addField(getParentActivity(), requiredType, documentTypes, true, true); updateManageVisibility(); } else { return; } } - HashMap values = typesValues.get(type); + HashMap values = typesValues.get(requiredType); + HashMap documentValues = documentRequiredType != null ? typesValues.get(documentRequiredType) : null; + TLRPC.TL_secureValue requiredTypeValue = getValueByType(requiredType, true); + TLRPC.TL_secureValue documentRequiredTypeValue = getValueByType(documentRequiredType, true); - if (json != null) { + if (json != null && languageMap == null) { languageMap = new HashMap<>(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(ApplicationLoader.applicationContext.getResources().getAssets().open("countries.txt"))); @@ -4233,177 +4999,222 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } String value = null; - if (json != null || documentsJson != null) { - if (values == null) { - return; + if (text != null) { + if (requiredType.type instanceof TLRPC.TL_secureValueTypePhone) { + value = PhoneFormat.getInstance().format("+" + text); + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeEmail) { + value = text; } - values.clear(); - String keys[] = null; - String documentKeys[] = null; - if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { - if (currentActivityType == TYPE_REQUEST || currentActivityType == TYPE_MANAGE && documentType == null) { - keys = new String[]{ - "first_name", - "last_name", - "birth_date", - "gender", - "country_code", - "residence_country_code" - }; + } else { + StringBuilder stringBuilder = null; + if (currentActivityType != TYPE_MANAGE && documentRequiredType != null && (!TextUtils.isEmpty(documentsJson) || documentRequiredTypeValue != null)) { + if (stringBuilder == null) { + stringBuilder = new StringBuilder(); } - if (currentActivityType == TYPE_REQUEST || currentActivityType == TYPE_MANAGE && documentType != null) { - documentKeys = new String[]{ - "document_no", - "expiry_date" - }; - } - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { - if (currentActivityType == TYPE_REQUEST || currentActivityType == TYPE_MANAGE && documentType == null) { - keys = new String[]{ - "street_line1", - "street_line2", - "post_code", - "city", - "state", - "country_code" - }; + if (availableDocumentTypesCount > 1) { + stringBuilder.append(getTextForType(documentRequiredType.type)); + } else if (TextUtils.isEmpty(documentsJson)) { + stringBuilder.append(LocaleController.getString("PassportDocuments", R.string.PassportDocuments)); } } - if (keys != null || documentKeys != null) { - try { - StringBuilder stringBuilder = null; - JSONObject jsonObject = null; - String currentKeys[] = null; - for (int b = 0; b < 2; b++) { - if (b == 0) { - if (json != null) { - jsonObject = new JSONObject(json); - currentKeys = keys; - } - } else { - if (documentsJson != null) { - jsonObject = new JSONObject(documentsJson); - currentKeys = documentKeys; - } - } - if (currentKeys == null) { - continue; - } - if (currentActivityType != TYPE_MANAGE && b == 0 && documentType != null && !TextUtils.isEmpty(documentsJson)) { - if (stringBuilder == null) { - stringBuilder = new StringBuilder(); - } - if (documentType instanceof TLRPC.TL_secureValueTypePassport) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentPassport", R.string.ActionBotDocumentPassport)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeDriverLicense) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentDriverLicence", R.string.ActionBotDocumentDriverLicence)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentIdentityCard", R.string.ActionBotDocumentIdentityCard)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeUtilityBill) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentUtilityBill", R.string.ActionBotDocumentUtilityBill)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeBankStatement) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentBankStatement", R.string.ActionBotDocumentBankStatement)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentRentalAgreement", R.string.ActionBotDocumentRentalAgreement)); - } else if (hasNotValueForType(TLRPC.TL_secureValueTypeInternalPassport.class)) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentInternalPassport", R.string.ActionBotDocumentInternalPassport)); - } else if (hasNotValueForType(TLRPC.TL_secureValueTypePassportRegistration.class)) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentPassportRegistration", R.string.ActionBotDocumentPassportRegistration)); - } else if (hasNotValueForType(TLRPC.TL_secureValueTypeTemporaryRegistration.class)) { - stringBuilder.append(LocaleController.getString("ActionBotDocumentTemporaryRegistration", R.string.ActionBotDocumentTemporaryRegistration)); - } - } - for (int a = 0; a < currentKeys.length; a++) { - if (jsonObject.has(currentKeys[a])) { - if (stringBuilder == null) { - stringBuilder = new StringBuilder(); + if (json != null || documentsJson != null) { + if (values == null) { + return; + } + values.clear(); + String keys[] = null; + String documentKeys[] = null; + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (currentActivityType == TYPE_REQUEST && !documentOnly || currentActivityType == TYPE_MANAGE && documentRequiredType == null) { + keys = new String[]{ + "first_name", + "middle_name", + "last_name", + "first_name_native", + "middle_name_native", + "last_name_native", + "birth_date", + "gender", + "country_code", + "residence_country_code" + }; + } + if (currentActivityType == TYPE_REQUEST || currentActivityType == TYPE_MANAGE && documentRequiredType != null) { + documentKeys = new String[]{ + "document_no", + "expiry_date" + }; + } + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + if (currentActivityType == TYPE_REQUEST && !documentOnly || currentActivityType == TYPE_MANAGE && documentRequiredType == null) { + keys = new String[]{ + "street_line1", + "street_line2", + "post_code", + "city", + "state", + "country_code" + }; + } + } + if (keys != null || documentKeys != null) { + try { + JSONObject jsonObject = null; + String currentKeys[] = null; + for (int b = 0; b < 2; b++) { + if (b == 0) { + if (json != null) { + jsonObject = new JSONObject(json); + currentKeys = keys; } - String jsonValue = jsonObject.getString(currentKeys[a]); - if (jsonValue != null) { - values.put(currentKeys[a], jsonValue); - if (!TextUtils.isEmpty(jsonValue)) { - if (stringBuilder.length() > 0) { - if ("last_name".equals(currentKeys[a])) { - stringBuilder.append(" "); - } else { - stringBuilder.append(", "); + } else { + if (documentValues == null) { + continue; + } + if (documentsJson != null) { + jsonObject = new JSONObject(documentsJson); + currentKeys = documentKeys; + } + } + if (currentKeys == null || jsonObject == null) { + continue; + } + try { + Iterator iter = jsonObject.keys(); + while (iter.hasNext()) { + String key = iter.next(); + if (b == 0) { + values.put(key, jsonObject.getString(key)); + } else { + documentValues.put(key, jsonObject.getString(key)); + } + } + } catch (Throwable e) { + FileLog.e(e); + } + + for (int a = 0; a < currentKeys.length; a++) { + if (jsonObject.has(currentKeys[a])) { + if (stringBuilder == null) { + stringBuilder = new StringBuilder(); + } + String jsonValue = jsonObject.getString(currentKeys[a]); + if (jsonValue != null) { + if (!TextUtils.isEmpty(jsonValue)) { + if ("first_name_native".equals(currentKeys[a]) || + "middle_name_native".equals(currentKeys[a]) || + "last_name_native".equals(currentKeys[a])) { + continue; } - } - switch (currentKeys[a]) { - case "country_code": - String country = languageMap.get(jsonValue); - if (country != null) { - stringBuilder.append(country); + if (stringBuilder.length() > 0) { + if ("last_name".equals(currentKeys[a]) || "last_name_native".equals(currentKeys[a]) || "middle_name".equals(currentKeys[a]) || "middle_name_native".equals(currentKeys[a])) { + stringBuilder.append(" "); + } else { + stringBuilder.append(", "); } - break; - case "gender": - if ("male".equals(jsonValue)) { - stringBuilder.append(LocaleController.getString("PassportMale", R.string.PassportMale)); - } else if ("female".equals(jsonValue)) { - stringBuilder.append(LocaleController.getString("PassportFemale", R.string.PassportFemale)); - } - break; - default: - stringBuilder.append(jsonValue); - break; + } + switch (currentKeys[a]) { + case "country_code": + case "residence_country_code": + String country = languageMap.get(jsonValue); + if (country != null) { + stringBuilder.append(country); + } + break; + case "gender": + if ("male".equals(jsonValue)) { + stringBuilder.append(LocaleController.getString("PassportMale", R.string.PassportMale)); + } else if ("female".equals(jsonValue)) { + stringBuilder.append(LocaleController.getString("PassportFemale", R.string.PassportFemale)); + } + break; + default: + stringBuilder.append(jsonValue); + break; + } } } } } } - } - if (stringBuilder != null) { - value = stringBuilder.toString(); - } - } catch (Exception ignore) { + } catch (Exception ignore) { + } } } - } else if (text != null) { - if (type instanceof TLRPC.TL_secureValueTypePhone) { - value = PhoneFormat.getInstance().format("+" + text); - } else if (type instanceof TLRPC.TL_secureValueTypeEmail) { - value = text; + if (stringBuilder != null) { + value = stringBuilder.toString(); } } boolean isError = false; - HashMap errors = errorsMap.get(getNameForType(type)); - HashMap documentsErrors = errorsMap.get(getNameForType(documentType)); + HashMap errors = !documentOnly ? errorsMap.get(getNameForType(requiredType.type)) : null; + HashMap documentsErrors = documentRequiredType != null ? errorsMap.get(getNameForType(documentRequiredType.type)) : null; if (errors != null && errors.size() > 0 || documentsErrors != null && documentsErrors.size() > 0) { - value = LocaleController.getString("PassportCorrectErrors", R.string.PassportCorrectErrors); - //value = getErrorsString(errors, documentsErrors); + value = null; + if (!documentOnly) { + value = mainErrorsMap.get(getNameForType(requiredType.type)); + } + if (value == null) { + value = mainErrorsMap.get(getNameForType(documentRequiredType.type)); + } isError = true; } else { - if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { if (TextUtils.isEmpty(value)) { - if (documentType == null) { + if (documentRequiredType == null) { value = LocaleController.getString("PassportPersonalDetailsInfo", R.string.PassportPersonalDetailsInfo); } else { if (currentActivityType == TYPE_MANAGE) { value = LocaleController.getString("PassportDocuments", R.string.PassportDocuments); } else { - value = LocaleController.getString("PassportIdentityDocumentInfo", R.string.PassportIdentityDocumentInfo); + if (availableDocumentTypesCount == 1) { + if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypePassport) { + value = LocaleController.getString("PassportIdentityPassport", R.string.PassportIdentityPassport); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { + value = LocaleController.getString("PassportIdentityInternalPassport", R.string.PassportIdentityInternalPassport); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { + value = LocaleController.getString("PassportIdentityDriverLicence", R.string.PassportIdentityDriverLicence); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + value = LocaleController.getString("PassportIdentityID", R.string.PassportIdentityID); + } + } else { + value = LocaleController.getString("PassportIdentityDocumentInfo", R.string.PassportIdentityDocumentInfo); + } } } } - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { if (TextUtils.isEmpty(value)) { - if (documentType == null) { + if (documentRequiredType == null) { value = LocaleController.getString("PassportAddressNoUploadInfo", R.string.PassportAddressNoUploadInfo); } else { if (currentActivityType == TYPE_MANAGE) { value = LocaleController.getString("PassportDocuments", R.string.PassportDocuments); } else { - value = LocaleController.getString("PassportAddressInfo", R.string.PassportAddressInfo); + if (availableDocumentTypesCount == 1) { + if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + value = LocaleController.getString("PassportAddAgreementInfo", R.string.PassportAddAgreementInfo); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeUtilityBill) { + value = LocaleController.getString("PassportAddBillInfo", R.string.PassportAddBillInfo); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypePassportRegistration) { + value = LocaleController.getString("PassportAddPassportRegistrationInfo", R.string.PassportAddPassportRegistrationInfo); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + value = LocaleController.getString("PassportAddTemporaryRegistrationInfo", R.string.PassportAddTemporaryRegistrationInfo); + } else if (documentRequiredType.type instanceof TLRPC.TL_secureValueTypeBankStatement) { + value = LocaleController.getString("PassportAddBankInfo", R.string.PassportAddBankInfo); + } + } else { + value = LocaleController.getString("PassportAddressInfo", R.string.PassportAddressInfo); + } } } } - } else if (type instanceof TLRPC.TL_secureValueTypePhone) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypePhone) { if (TextUtils.isEmpty(value)) { value = LocaleController.getString("PassportPhoneInfo", R.string.PassportPhoneInfo); } - } else if (type instanceof TLRPC.TL_secureValueTypeEmail) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeEmail) { if (TextUtils.isEmpty(value)) { value = LocaleController.getString("PassportEmailInfo", R.string.PassportEmailInfo); } @@ -4411,7 +5222,97 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } view.setValue(value); view.valueTextView.setTextColor(Theme.getColor(isError ? Theme.key_windowBackgroundWhiteRedText3 : Theme.key_windowBackgroundWhiteGrayText2)); - view.setChecked(!isError && currentActivityType != TYPE_MANAGE && getValueByType(type, true) != null && (documentType == null || getValueByType(documentType, true) != null)); + view.setChecked(!isError && currentActivityType != TYPE_MANAGE && (documentOnly && documentRequiredType != null || !documentOnly && requiredTypeValue != null) && (documentRequiredType == null || documentRequiredTypeValue != null)); + } + + private void checkNativeFields(boolean byEdit) { + if (inputExtraFields == null) { + return; + } + String country = languageMap.get(currentResidence); + HashMap map = SharedConfig.getCountryLangs(); + String lang = map.get(currentResidence); + + if (!currentType.native_names || TextUtils.isEmpty(currentResidence) || "EN".equals(lang)) { + if (nativeInfoCell.getVisibility() != View.GONE) { + nativeInfoCell.setVisibility(View.GONE); + headerCell.setVisibility(View.GONE); + extraBackgroundView2.setVisibility(View.GONE); + for (int a = 0; a < inputExtraFields.length; a++) { + ((View) inputExtraFields[a].getParent()).setVisibility(View.GONE); + } + + if ((currentBotId != 0 || currentDocumentsType == null) && currentTypeValue != null && !documentOnly || currentDocumentsTypeValue != null) { + sectionCell2.setBackgroundDrawable(Theme.getThemedDrawable(getParentActivity(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + } else { + sectionCell2.setBackgroundDrawable(Theme.getThemedDrawable(getParentActivity(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } + } + } else { + if (nativeInfoCell.getVisibility() != View.VISIBLE) { + nativeInfoCell.setVisibility(View.VISIBLE); + headerCell.setVisibility(View.VISIBLE); + extraBackgroundView2.setVisibility(View.VISIBLE); + for (int a = 0; a < inputExtraFields.length; a++) { + ((View) inputExtraFields[a].getParent()).setVisibility(View.VISIBLE); + } + if (inputExtraFields[FIELD_NATIVE_NAME].length() == 0 && inputExtraFields[FIELD_NATIVE_MIDNAME].length() == 0 && inputExtraFields[FIELD_NATIVE_SURNAME].length() == 0) { + for (int a = 0; a < nonLatinNames.length; a++) { + if (nonLatinNames[a]) { + inputExtraFields[FIELD_NATIVE_NAME].setText(inputFields[FIELD_NAME].getText()); + inputExtraFields[FIELD_NATIVE_MIDNAME].setText(inputFields[FIELD_MIDNAME].getText()); + inputExtraFields[FIELD_NATIVE_SURNAME].setText(inputFields[FIELD_SURNAME].getText()); + break; + } + } + } + sectionCell2.setBackgroundDrawable(Theme.getThemedDrawable(getParentActivity(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + } + + nativeInfoCell.setText(LocaleController.formatString("PassportNativeInfo", R.string.PassportNativeInfo, country)); + + + String header = lang != null ? LocaleController.getServerString("PassportLanguage_" + lang) : null; + if (header != null) { + headerCell.setText(LocaleController.formatString("PassportNativeHeaderLang", R.string.PassportNativeHeaderLang, header)); + } else { + headerCell.setText(LocaleController.getString("PassportNativeHeader", R.string.PassportNativeHeader)); + } + for (int a = 0; a < FIELD_NATIVE_COUNT; a++) { + switch (a) { + case FIELD_NATIVE_NAME: + if (header != null) { + inputExtraFields[a].setHintText(LocaleController.getString("PassportName", R.string.PassportName)); + } else { + inputExtraFields[a].setHintText(LocaleController.formatString("PassportNameCountry", R.string.PassportNameCountry, country)); + } + break; + case FIELD_NATIVE_MIDNAME: + if (header != null) { + inputExtraFields[a].setHintText(LocaleController.getString("PassportMidname", R.string.PassportMidname)); + } else { + inputExtraFields[a].setHintText(LocaleController.formatString("PassportMidnameCountry", R.string.PassportMidnameCountry, country)); + } + break; + case FIELD_NATIVE_SURNAME: + if (header != null) { + inputExtraFields[a].setHintText(LocaleController.getString("PassportSurname", R.string.PassportSurname)); + } else { + inputExtraFields[a].setHintText(LocaleController.formatString("PassportSurnameCountry", R.string.PassportSurnameCountry, country)); + } + break; + } + } + + if (byEdit) { + AndroidUtilities.runOnUIThread(() -> { + if (inputExtraFields != null) { + scrollToField(inputExtraFields[FIELD_NATIVE_NAME]); + } + }); + + } + } } private String getErrorsString(HashMap errors, HashMap documentErrors) { @@ -4444,56 +5345,94 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return stringBuilder.toString(); } - private TLRPC.TL_secureValue getValueByType(TLRPC.SecureValueType type, boolean check) { - if (type == null) { + private TLRPC.TL_secureValue getValueByType(TLRPC.TL_secureRequiredType requiredType, boolean check) { + if (requiredType == null) { return null; } for (int a = 0, size = currentForm.values.size(); a < size; a++) { TLRPC.TL_secureValue secureValue = currentForm.values.get(a); - if (type.getClass() == secureValue.type.getClass()) { + if (requiredType.type.getClass() == secureValue.type.getClass()) { if (check) { - if (currentForm.selfie_required && - (type instanceof TLRPC.TL_secureValueTypeDriverLicense || - type instanceof TLRPC.TL_secureValueTypePassport || - type instanceof TLRPC.TL_secureValueTypeInternalPassport || - type instanceof TLRPC.TL_secureValueTypeIdentityCard)) { + if (requiredType.selfie_required) { if (!(secureValue.selfie instanceof TLRPC.TL_secureFile)) { return null; } } - if (type instanceof TLRPC.TL_secureValueTypeUtilityBill || - type instanceof TLRPC.TL_secureValueTypeBankStatement || - type instanceof TLRPC.TL_secureValueTypePassportRegistration || - type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration || - type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + if (requiredType.translation_required) { + if (secureValue.translation.isEmpty()) { + return null; + } + } + if (isAddressDocument(requiredType.type)) { if (secureValue.files.isEmpty()) { return null; } } - if (type instanceof TLRPC.TL_secureValueTypeDriverLicense || - type instanceof TLRPC.TL_secureValueTypePassport || - type instanceof TLRPC.TL_secureValueTypeInternalPassport || - type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + if (isPersonalDocument(requiredType.type)) { if (!(secureValue.front_side instanceof TLRPC.TL_secureFile)) { return null; } } - if (type instanceof TLRPC.TL_secureValueTypeDriverLicense || - type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + if (requiredType.type instanceof TLRPC.TL_secureValueTypeDriverLicense || requiredType.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { if (!(secureValue.reverse_side instanceof TLRPC.TL_secureFile)) { return null; } } + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails || requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + String[] keys; + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (requiredType.native_names) { + keys = new String[]{ + "first_name_native", + "last_name_native", + "birth_date", + "gender", + "country_code", + "residence_country_code" + }; + } else { + keys = new String[]{ + "first_name", + "last_name", + "birth_date", + "gender", + "country_code", + "residence_country_code" + }; + } + } else { + keys = new String[]{ + "street_line1", + "street_line2", + "post_code", + "city", + "state", + "country_code" + }; + } + try { + JSONObject jsonObject = new JSONObject(decryptData(secureValue.data.data, decryptValueSecret(secureValue.data.secret, secureValue.data.data_hash), secureValue.data.data_hash)); + for (int b = 0; b < keys.length; b++) { + if (!jsonObject.has(keys[b]) || TextUtils.isEmpty(jsonObject.getString(keys[b]))) { + return null; + } + } + } catch (Throwable ignore) { + return null; + } + } } - return secureValue; } } return null; } - private void openTypeActivity(TLRPC.SecureValueType type, TLRPC.SecureValueType documentsType, ArrayList availableDocumentTypes) { + private void openTypeActivity(TLRPC.TL_secureRequiredType requiredType, TLRPC.TL_secureRequiredType documentRequiredType, ArrayList availableDocumentTypes, boolean documentOnly) { int activityType = -1; + final int availableDocumentTypesCount = availableDocumentTypes != null ? availableDocumentTypes.size() : 0; + TLRPC.SecureValueType type = requiredType.type; + TLRPC.SecureValueType documentType = documentRequiredType != null ? documentRequiredType.type : null; if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { activityType = TYPE_IDENTITY; } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { @@ -4504,12 +5443,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter activityType = TYPE_EMAIL; } if (activityType != -1) { - HashMap errors = errorsMap.get(getNameForType(type)); - HashMap documentsErrors = errorsMap.get(getNameForType(documentsType)); - TLRPC.TL_secureValue value = getValueByType(type, false); - TLRPC.TL_secureValue documentsValue = getValueByType(documentsType, false); + HashMap errors = !documentOnly ? errorsMap.get(getNameForType(type)) : null; + HashMap documentsErrors = errorsMap.get(getNameForType(documentType)); + TLRPC.TL_secureValue value = getValueByType(requiredType, false); + TLRPC.TL_secureValue documentsValue = getValueByType(documentRequiredType, false); - final PassportActivity activity = new PassportActivity(activityType, currentForm, currentPassword, type, value, documentsType, documentsValue, typesValues.get(type)); + final PassportActivity activity = new PassportActivity(activityType, currentForm, currentPassword, requiredType, value, documentRequiredType, documentsValue, typesValues.get(requiredType), documentRequiredType != null ? typesValues.get(documentRequiredType) : null); activity.delegate = new PassportActivityDelegate() { private TLRPC.InputSecureFile getInputSecureFile(SecureDocument document) { @@ -4539,12 +5478,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } @Override - public void saveValue(final TLRPC.SecureValueType type, final String text, final String json, final TLRPC.SecureValueType documentsType, final String documentsJson, final ArrayList documents, final SecureDocument selfie, final SecureDocument front, final SecureDocument reverse, final Runnable finishRunnable, final ErrorRunnable errorRunnable) { + public void saveValue(final TLRPC.TL_secureRequiredType requiredType, final String text, final String json, final TLRPC.TL_secureRequiredType documentRequiredType, final String documentsJson, final ArrayList documents, final SecureDocument selfie, final ArrayList translationDocuments, final SecureDocument front, final SecureDocument reverse, final Runnable finishRunnable, final ErrorRunnable errorRunnable) { TLRPC.TL_inputSecureValue inputSecureValue = null; if (!TextUtils.isEmpty(json)) { inputSecureValue = new TLRPC.TL_inputSecureValue(); - inputSecureValue.type = type; + inputSecureValue.type = requiredType.type; inputSecureValue.flags |= 1; EncryptionResult result = encryptData(AndroidUtilities.getStringBytes(json)); @@ -4566,13 +5505,13 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return; } inputSecureValue = new TLRPC.TL_inputSecureValue(); - inputSecureValue.type = type; + inputSecureValue.type = requiredType.type; inputSecureValue.flags |= 32; inputSecureValue.plain_data = plainData; } - if (inputSecureValue == null) { + if (!documentOnly && inputSecureValue == null) { if (errorRunnable != null) { errorRunnable.onError(null, null); } @@ -4580,9 +5519,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } TLRPC.TL_inputSecureValue fileInputSecureValue; - if (documentsType != null) { + if (documentRequiredType != null) { fileInputSecureValue = new TLRPC.TL_inputSecureValue(); - fileInputSecureValue.type = documentsType; + fileInputSecureValue.type = documentRequiredType.type; if (!TextUtils.isEmpty(documentsJson)) { fileInputSecureValue.flags |= 1; @@ -4606,6 +5545,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter fileInputSecureValue.selfie = getInputSecureFile(selfie); fileInputSecureValue.flags |= 8; } + if (translationDocuments != null && !translationDocuments.isEmpty()) { + fileInputSecureValue.flags |= 64; + for (int a = 0, size = translationDocuments.size(); a < size; a++) { + fileInputSecureValue.translation.add(getInputSecureFile(translationDocuments.get(a))); + } + } if (documents != null && !documents.isEmpty()) { fileInputSecureValue.flags |= 16; for (int a = 0, size = documents.size(); a < size; a++) { @@ -4613,7 +5558,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - if (currentActivityType == TYPE_MANAGE) { + if (documentOnly) { inputSecureValue = fileInputSecureValue; fileInputSecureValue = null; } @@ -4630,71 +5575,85 @@ public class PassportActivity extends BaseFragment implements NotificationCenter ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { private void onResult(final TLRPC.TL_error error, final TLRPC.TL_secureValue newValue, final TLRPC.TL_secureValue newPendingValue) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error != null) { - if (errorRunnable != null) { - errorRunnable.onError(error.text, text); - } - AlertsCreator.processError(currentAccount, error, PassportActivity.this, req, text); - } else { - if (currentActivityType == TYPE_MANAGE) { - if (documentsType != null) { - removeValue(documentsType); - } else { - removeValue(type); - } + AndroidUtilities.runOnUIThread(() -> { + if (error != null) { + if (errorRunnable != null) { + errorRunnable.onError(error.text, text); + } + AlertsCreator.processError(currentAccount, error, PassportActivity.this, req, text); + } else { + if (documentOnly) { + if (documentRequiredType != null) { + removeValue(documentRequiredType); } else { - removeValue(type); - removeValue(documentsType); + removeValue(requiredType); } - if (newValue != null) { - currentForm.values.add(newValue); - } - if (newPendingValue != null) { - currentForm.values.add(newPendingValue); - } - if (documents != null && !documents.isEmpty()) { - for (int a = 0, size = documents.size(); a < size; a++) { - SecureDocument document = documents.get(a); - if (document.inputFile != null) { - for (int b = 0, size2 = newValue.files.size(); b < size2; b++) { - TLRPC.SecureFile file = newValue.files.get(b); - if (file instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) file; - if (Utilities.arraysEquals(document.fileSecret, 0, secureFile.secret, 0)) { - renameFile(document, secureFile); - break; - } + } else { + removeValue(requiredType); + removeValue(documentRequiredType); + } + if (newValue != null) { + currentForm.values.add(newValue); + } + if (newPendingValue != null) { + currentForm.values.add(newPendingValue); + } + if (documents != null && !documents.isEmpty()) { + for (int a = 0, size = documents.size(); a < size; a++) { + SecureDocument document = documents.get(a); + if (document.inputFile != null) { + for (int b = 0, size2 = newValue.files.size(); b < size2; b++) { + TLRPC.SecureFile file = newValue.files.get(b); + if (file instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) file; + if (Utilities.arraysEquals(document.fileSecret, 0, secureFile.secret, 0)) { + renameFile(document, secureFile); + break; } } } } } - if (selfie != null && selfie.inputFile != null && newValue.selfie instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.selfie; - if (Utilities.arraysEquals(selfie.fileSecret, 0, secureFile.secret, 0)) { - renameFile(selfie, secureFile); - } - } - if (front != null && front.inputFile != null && newValue.front_side instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.front_side; - if (Utilities.arraysEquals(front.fileSecret, 0, secureFile.secret, 0)) { - renameFile(front, secureFile); - } - } - if (reverse != null && reverse.inputFile != null && newValue.reverse_side instanceof TLRPC.TL_secureFile) { - TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.reverse_side; - if (Utilities.arraysEquals(reverse.fileSecret, 0, secureFile.secret, 0)) { - renameFile(reverse, secureFile); + } + if (selfie != null && selfie.inputFile != null && newValue.selfie instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.selfie; + if (Utilities.arraysEquals(selfie.fileSecret, 0, secureFile.secret, 0)) { + renameFile(selfie, secureFile); + } + } + if (front != null && front.inputFile != null && newValue.front_side instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.front_side; + if (Utilities.arraysEquals(front.fileSecret, 0, secureFile.secret, 0)) { + renameFile(front, secureFile); + } + } + if (reverse != null && reverse.inputFile != null && newValue.reverse_side instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) newValue.reverse_side; + if (Utilities.arraysEquals(reverse.fileSecret, 0, secureFile.secret, 0)) { + renameFile(reverse, secureFile); + } + } + if (translationDocuments != null && !translationDocuments.isEmpty()) { + for (int a = 0, size = translationDocuments.size(); a < size; a++) { + SecureDocument document = translationDocuments.get(a); + if (document.inputFile != null) { + for (int b = 0, size2 = newValue.translation.size(); b < size2; b++) { + TLRPC.SecureFile file = newValue.translation.get(b); + if (file instanceof TLRPC.TL_secureFile) { + TLRPC.TL_secureFile secureFile = (TLRPC.TL_secureFile) file; + if (Utilities.arraysEquals(document.fileSecret, 0, secureFile.secret, 0)) { + renameFile(document, secureFile); + break; + } + } + } } } + } - setTypeValue(type, text, json, documentsType, documentsJson); - if (finishRunnable != null) { - finishRunnable.run(); - } + setTypeValue(requiredType, text, json, documentRequiredType, documentsJson, documentOnly, availableDocumentTypesCount); + if (finishRunnable != null) { + finishRunnable.run(); } } }); @@ -4706,43 +5665,29 @@ public class PassportActivity extends BaseFragment implements NotificationCenter if (error.text.equals("EMAIL_VERIFICATION_NEEDED")) { TLRPC.TL_account_sendVerifyEmailCode req = new TLRPC.TL_account_sendVerifyEmailCode(); req.email = text; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (response != null) { - TLRPC.TL_account_sentEmailCode res = (TLRPC.TL_account_sentEmailCode) response; - HashMap values = new HashMap<>(); - values.put("email", text); - values.put("pattern", res.email_pattern); - PassportActivity activity = new PassportActivity(TYPE_EMAIL_VERIFICATION, currentForm, currentPassword, type, null, null, null, values); - activity.currentAccount = currentAccount; - activity.emailCodeLength = res.length; - activity.saltedPassword = saltedPassword; - activity.secureSecret = secureSecret; - activity.delegate = currentDelegate; - presentFragment(activity, true); - } else { - showAlertWithText(LocaleController.getString("PassportEmail", R.string.PassportEmail), error.text); - if (errorRunnable != null) { - errorRunnable.onError(error.text, text); - } - } - } - }); - + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { + if (response1 != null) { + TLRPC.TL_account_sentEmailCode res = (TLRPC.TL_account_sentEmailCode) response1; + HashMap values = new HashMap<>(); + values.put("email", text); + values.put("pattern", res.email_pattern); + PassportActivity activity1 = new PassportActivity(TYPE_EMAIL_VERIFICATION, currentForm, currentPassword, requiredType, null, null, null, values, null); + activity1.currentAccount = currentAccount; + activity1.emailCodeLength = res.length; + activity1.saltedPassword = saltedPassword; + activity1.secureSecret = secureSecret; + activity1.delegate = currentDelegate; + presentFragment(activity1, true); + } else { + showAlertWithText(LocaleController.getString("PassportEmail", R.string.PassportEmail), error1.text); + if (errorRunnable != null) { + errorRunnable.onError(error1.text, text); + } } - }); + })); return; } else if (error.text.equals("PHONE_VERIFICATION_NEEDED")) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - errorRunnable.onError(error.text, text); - } - }); + AndroidUtilities.runOnUIThread(() -> errorRunnable.onError(error.text, text)); return; } } @@ -4751,12 +5696,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter final TLRPC.TL_account_saveSecureValue req = new TLRPC.TL_account_saveSecureValue(); req.value = finalFileInputSecureValue; req.secure_secret_id = secureSecretId; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - onResult(error, (TLRPC.TL_secureValue) response, pendingValue); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response12, error12) -> onResult(error12, (TLRPC.TL_secureValue) response12, pendingValue)); } else { onResult(error, (TLRPC.TL_secureValue) response, null); } @@ -4772,8 +5712,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } @Override - public void deleteValue(TLRPC.SecureValueType type, TLRPC.SecureValueType documentsType, boolean deleteType, Runnable finishRunnable, ErrorRunnable errorRunnable) { - deleteValueInternal(type, documentsType, deleteType, finishRunnable, errorRunnable); + public void deleteValue(TLRPC.TL_secureRequiredType requiredType, TLRPC.TL_secureRequiredType documentRequiredType, ArrayList documentRequiredTypes, boolean deleteType, Runnable finishRunnable, ErrorRunnable errorRunnable) { + deleteValueInternal(requiredType, documentRequiredType, documentRequiredTypes, deleteType, finishRunnable, errorRunnable, documentOnly); } }; activity.currentAccount = currentAccount; @@ -4781,6 +5721,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter activity.secureSecret = secureSecret; activity.currentBotId = currentBotId; activity.fieldsErrors = errors; + activity.documentOnly = documentOnly; activity.documentsErrors = documentsErrors; activity.availableDocumentTypes = availableDocumentTypes; if (activityType == TYPE_EMAIL) { @@ -4790,140 +5731,133 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - private TLRPC.TL_secureValue removeValue(TLRPC.SecureValueType type) { - if (type == null) { + private TLRPC.TL_secureValue removeValue(TLRPC.TL_secureRequiredType requiredType) { + if (requiredType == null) { return null; } for (int a = 0, size = currentForm.values.size(); a < size; a++) { TLRPC.TL_secureValue secureValue = currentForm.values.get(a); - if (type.getClass() == secureValue.type.getClass()) { + if (requiredType.type.getClass() == secureValue.type.getClass()) { return currentForm.values.remove(a); } } return null; } - private void deleteValueInternal(final TLRPC.SecureValueType type, final TLRPC.SecureValueType documentsType, final boolean deleteType, final Runnable finishRunnable, final ErrorRunnable errorRunnable) { - if (type == null) { + private void deleteValueInternal(final TLRPC.TL_secureRequiredType requiredType, final TLRPC.TL_secureRequiredType documentRequiredType, final ArrayList documentRequiredTypes, final boolean deleteType, final Runnable finishRunnable, final ErrorRunnable errorRunnable, boolean documentOnly) { + if (requiredType == null) { return; } TLRPC.TL_account_deleteSecureValue req = new TLRPC.TL_account_deleteSecureValue(); - if (currentActivityType == TYPE_MANAGE && documentsType != null) { - req.types.add(documentsType); + if (documentOnly && documentRequiredType != null) { + req.types.add(documentRequiredType.type); } else { if (deleteType) { - req.types.add(type); + req.types.add(requiredType.type); } - if (documentsType != null) { - req.types.add(documentsType); + if (documentRequiredType != null) { + req.types.add(documentRequiredType.type); } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error != null) { - if (errorRunnable != null) { - errorRunnable.onError(error.text, null); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } else { - if (currentActivityType == TYPE_MANAGE) { - if (documentsType != null) { - removeValue(documentsType); - } else { - removeValue(type); - } - } else { - if (deleteType) { - removeValue(type); - } - removeValue(documentsType); - } - if (currentActivityType == TYPE_MANAGE) { - TextDetailSecureCell view = typesViews.remove(type); - if (view != null) { - linearLayout2.removeView(view); - View child = linearLayout2.getChildAt(linearLayout2.getChildCount() - 6); - if (child instanceof TextDetailSecureCell) { - ((TextDetailSecureCell) child).setNeedDivider(false); - } - } - updateManageVisibility(); - } else { - if (deleteType) { - setTypeValue(type, null, null, documentsType, null); - } else { - String json = null; - TLRPC.TL_secureValue value = getValueByType(type, false); - if (value != null && value.data != null) { - json = decryptData(value.data.data, decryptValueSecret(value.data.secret, value.data.data_hash), value.data.data_hash); - } - setTypeValue(type, null, json, documentsType, null); - } - } - if (finishRunnable != null) { - finishRunnable.run(); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null) { + if (errorRunnable != null) { + errorRunnable.onError(error.text, null); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); + } else { + if (documentOnly) { + if (documentRequiredType != null) { + removeValue(documentRequiredType); + } else { + removeValue(requiredType); + } + } else { + if (deleteType) { + removeValue(requiredType); + } + removeValue(documentRequiredType); + } + if (currentActivityType == TYPE_MANAGE) { + TextDetailSecureCell view = typesViews.remove(requiredType); + if (view != null) { + linearLayout2.removeView(view); + View child = linearLayout2.getChildAt(linearLayout2.getChildCount() - 6); + if (child instanceof TextDetailSecureCell) { + ((TextDetailSecureCell) child).setNeedDivider(false); } } - }); + updateManageVisibility(); + } else { + + String documentJson = null; + TLRPC.TL_secureRequiredType documentsType = documentRequiredType; + if (documentsType != null && documentRequiredTypes != null && documentRequiredTypes.size() > 1) { + for (int a = 0, count = documentRequiredTypes.size(); a < count; a++) { + TLRPC.TL_secureRequiredType documentType = documentRequiredTypes.get(a); + TLRPC.TL_secureValue documentValue = getValueByType(documentType, false); + if (documentValue != null) { + if (documentValue.data != null) { + documentJson = decryptData(documentValue.data.data, decryptValueSecret(documentValue.data.secret, documentValue.data.data_hash), documentValue.data.data_hash); + } + documentsType = documentType; + break; + } + } + if (documentsType == null) { + documentsType = documentRequiredTypes.get(0); + } + } + + if (deleteType) { + setTypeValue(requiredType, null, null, documentsType, documentJson, documentOnly, documentRequiredTypes != null ? documentRequiredTypes.size() : 0); + } else { + String json = null; + TLRPC.TL_secureValue value = getValueByType(requiredType, false); + if (value != null && value.data != null) { + json = decryptData(value.data.data, decryptValueSecret(value.data.secret, value.data.data_hash), value.data.data_hash); + } + setTypeValue(requiredType, null, json, documentsType, documentJson, documentOnly, documentRequiredTypes != null ? documentRequiredTypes.size() : 0); + } + } + if (finishRunnable != null) { + finishRunnable.run(); + } } - }); + })); } - private TextDetailSecureCell addField(Context context, final TLRPC.SecureValueType type, final ArrayList documentTypes, boolean last) { + private TextDetailSecureCell addField(Context context, final TLRPC.TL_secureRequiredType requiredType, final ArrayList documentRequiredTypes, boolean documentOnly, boolean last) { + final int availableDocumentTypesCount = documentRequiredTypes != null ? documentRequiredTypes.size() : 0; TextDetailSecureCell view = new TextDetailSecureCell(context); view.setBackgroundDrawable(Theme.getSelectorDrawable(true)); - if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { String text; - if (documentTypes == null || documentTypes.isEmpty()) { + if (documentRequiredTypes == null || documentRequiredTypes.isEmpty()) { text = LocaleController.getString("PassportPersonalDetails", R.string.PassportPersonalDetails); - } else if (documentTypes.size() == 1) { - TLRPC.SecureValueType documentType = documentTypes.get(0); - if (documentType instanceof TLRPC.TL_secureValueTypePassport) { - text = LocaleController.getString("ActionBotDocumentPassport", R.string.ActionBotDocumentPassport); - } else if (documentType instanceof TLRPC.TL_secureValueTypeDriverLicense) { - text = LocaleController.getString("ActionBotDocumentDriverLicence", R.string.ActionBotDocumentDriverLicence); - } else if (documentType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - text = LocaleController.getString("ActionBotDocumentIdentityCard", R.string.ActionBotDocumentIdentityCard); - } else if (documentType instanceof TLRPC.TL_secureValueTypeInternalPassport) { - text = LocaleController.getString("ActionBotDocumentInternalPassport", R.string.ActionBotDocumentInternalPassport); - } else { - text = "LOC_ERR: NO NAME FOR ID TYPE"; - } + } else if (documentOnly && documentRequiredTypes.size() == 1) { + text = getTextForType(documentRequiredTypes.get(0).type); + } else if (documentOnly && documentRequiredTypes.size() == 2) { + text = LocaleController.formatString("PassportTwoDocuments", R.string.PassportTwoDocuments, getTextForType(documentRequiredTypes.get(0).type), getTextForType(documentRequiredTypes.get(1).type)); } else { text = LocaleController.getString("PassportIdentityDocument", R.string.PassportIdentityDocument); } view.setTextAndValue(text, "", !last); - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { String text; - if (documentTypes == null || documentTypes.isEmpty()) { + if (documentRequiredTypes == null || documentRequiredTypes.isEmpty()) { text = LocaleController.getString("PassportAddress", R.string.PassportAddress); - } else if (documentTypes.size() == 1) { - TLRPC.SecureValueType documentType = documentTypes.get(0); - if (documentType instanceof TLRPC.TL_secureValueTypeUtilityBill) { - text = LocaleController.getString("ActionBotDocumentUtilityBill", R.string.ActionBotDocumentUtilityBill); - } else if (documentType instanceof TLRPC.TL_secureValueTypeBankStatement) { - text = LocaleController.getString("ActionBotDocumentBankStatement", R.string.ActionBotDocumentBankStatement); - } else if (documentType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - text = LocaleController.getString("ActionBotDocumentRentalAgreement", R.string.ActionBotDocumentRentalAgreement); - } else if (documentType instanceof TLRPC.TL_secureValueTypePassportRegistration) { - text = LocaleController.getString("ActionBotDocumentPassportRegistration", R.string.ActionBotDocumentPassportRegistration); - } else if (documentType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { - text = LocaleController.getString("ActionBotDocumentTemporaryRegistration", R.string.ActionBotDocumentTemporaryRegistration); - } else { - text = "LOC_ERR: NO NAME FOR ADDRESS TYPE"; - } + } else if (documentOnly && documentRequiredTypes.size() == 1) { + text = getTextForType(documentRequiredTypes.get(0).type); + } else if (documentOnly && documentRequiredTypes.size() == 2) { + text = LocaleController.formatString("PassportTwoDocuments", R.string.PassportTwoDocuments, getTextForType(documentRequiredTypes.get(0).type), getTextForType(documentRequiredTypes.get(1).type)); } else { text = LocaleController.getString("PassportResidentialAddress", R.string.PassportResidentialAddress); } view.setTextAndValue(text, "", !last); - } else if (type instanceof TLRPC.TL_secureValueTypePhone) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypePhone) { view.setTextAndValue(LocaleController.getString("PassportPhone", R.string.PassportPhone), "", !last); - } else if (type instanceof TLRPC.TL_secureValueTypeEmail) { + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeEmail) { view.setTextAndValue(LocaleController.getString("PassportEmail", R.string.PassportEmail), "", !last); } if (currentActivityType == TYPE_MANAGE) { @@ -4931,105 +5865,84 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } else { linearLayout2.addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - TLRPC.SecureValueType documentsType = null; - if (documentTypes != null) { - for (int a = 0, count = documentTypes.size(); a < count; a++) { - TLRPC.SecureValueType documentType = documentTypes.get(a); - if (getValueByType(documentType, false) != null || count == 1) { - documentsType = documentType; - break; - } + view.setOnClickListener(v -> { + TLRPC.TL_secureRequiredType documentsType = null; + if (documentRequiredTypes != null) { + for (int a = 0, count = documentRequiredTypes.size(); a < count; a++) { + TLRPC.TL_secureRequiredType documentType = documentRequiredTypes.get(a); + if (getValueByType(documentType, false) != null || count == 1) { + documentsType = documentType; + break; } } - if (type instanceof TLRPC.TL_secureValueTypePersonalDetails || type instanceof TLRPC.TL_secureValueTypeAddress) { - if (documentsType == null && documentTypes != null && !documentTypes.isEmpty()) { + } + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails || requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + if (documentsType == null && documentRequiredTypes != null && !documentRequiredTypes.isEmpty()) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); + + if (requiredType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { + builder.setTitle(LocaleController.getString("PassportIdentityDocument", R.string.PassportIdentityDocument)); + } else if (requiredType.type instanceof TLRPC.TL_secureValueTypeAddress) { + builder.setTitle(LocaleController.getString("PassportAddress", R.string.PassportAddress)); + } + + ArrayList strings = new ArrayList<>(); + for (int a = 0, count = documentRequiredTypes.size(); a < count; a++) { + TLRPC.TL_secureRequiredType documentType = documentRequiredTypes.get(a); + if (documentType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { + strings.add(LocaleController.getString("PassportAddLicence", R.string.PassportAddLicence)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypePassport) { + strings.add(LocaleController.getString("PassportAddPassport", R.string.PassportAddPassport)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { + strings.add(LocaleController.getString("PassportAddInternalPassport", R.string.PassportAddInternalPassport)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + strings.add(LocaleController.getString("PassportAddCard", R.string.PassportAddCard)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeUtilityBill) { + strings.add(LocaleController.getString("PassportAddBill", R.string.PassportAddBill)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeBankStatement) { + strings.add(LocaleController.getString("PassportAddBank", R.string.PassportAddBank)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeRentalAgreement) { + strings.add(LocaleController.getString("PassportAddAgreement", R.string.PassportAddAgreement)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { + strings.add(LocaleController.getString("PassportAddTemporaryRegistration", R.string.PassportAddTemporaryRegistration)); + } else if (documentType.type instanceof TLRPC.TL_secureValueTypePassportRegistration) { + strings.add(LocaleController.getString("PassportAddPassportRegistration", R.string.PassportAddPassportRegistration)); + } + } + + builder.setItems(strings.toArray(new CharSequence[strings.size()]), (dialog, which) -> openTypeActivity(requiredType, documentRequiredTypes.get(which), documentRequiredTypes, documentOnly)); + showDialog(builder.create()); + return; + } + } else { + boolean phoneField; + if ((phoneField = (requiredType.type instanceof TLRPC.TL_secureValueTypePhone)) || requiredType.type instanceof TLRPC.TL_secureValueTypeEmail) { + final TLRPC.TL_secureValue value = getValueByType(requiredType, false); + if (value != null) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - - if (type instanceof TLRPC.TL_secureValueTypePersonalDetails) { - builder.setTitle(LocaleController.getString("PassportIdentityDocument", R.string.PassportIdentityDocument)); - } else if (type instanceof TLRPC.TL_secureValueTypeAddress) { - builder.setTitle(LocaleController.getString("PassportAddress", R.string.PassportAddress)); - } - - ArrayList strings = new ArrayList<>(); - for (int a = 0, count = documentTypes.size(); a < count; a++) { - TLRPC.SecureValueType documentType = documentTypes.get(a); - if (documentType instanceof TLRPC.TL_secureValueTypeDriverLicense) { - strings.add(LocaleController.getString("PassportAddLicence", R.string.PassportAddLicence)); - } else if (documentType instanceof TLRPC.TL_secureValueTypePassport) { - strings.add(LocaleController.getString("PassportAddPassport", R.string.PassportAddPassport)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeInternalPassport) { - strings.add(LocaleController.getString("PassportAddInternalPassport", R.string.PassportAddInternalPassport)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeIdentityCard) { - strings.add(LocaleController.getString("PassportAddCard", R.string.PassportAddCard)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeUtilityBill) { - strings.add(LocaleController.getString("PassportAddBill", R.string.PassportAddBill)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeBankStatement) { - strings.add(LocaleController.getString("PassportAddBank", R.string.PassportAddBank)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeRentalAgreement) { - strings.add(LocaleController.getString("PassportAddAgreement", R.string.PassportAddAgreement)); - } else if (documentType instanceof TLRPC.TL_secureValueTypeTemporaryRegistration) { - strings.add(LocaleController.getString("PassportAddTemporaryRegistration", R.string.PassportAddTemporaryRegistration)); - } else if (documentType instanceof TLRPC.TL_secureValueTypePassportRegistration) { - strings.add(LocaleController.getString("PassportAddPassportRegistration", R.string.PassportAddPassportRegistration)); - } - } - - builder.setItems(strings.toArray(new CharSequence[strings.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - openTypeActivity(type, documentTypes.get(which), documentTypes); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + needShowProgress(); + deleteValueInternal(requiredType, null, null, true, this::needHideProgress, (error, text) -> needHideProgress(), documentOnly); }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(phoneField ? LocaleController.getString("PassportDeletePhoneAlert", R.string.PassportDeletePhoneAlert) : LocaleController.getString("PassportDeleteEmailAlert", R.string.PassportDeleteEmailAlert)); showDialog(builder.create()); return; } - } else { - boolean phoneField; - if ((phoneField = (type instanceof TLRPC.TL_secureValueTypePhone)) || type instanceof TLRPC.TL_secureValueTypeEmail) { - final TLRPC.TL_secureValue value = getValueByType(type, false); - if (value != null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - needShowProgress(); - deleteValueInternal(type, null, true, new Runnable() { - @Override - public void run() { - needHideProgress(); - } - }, new ErrorRunnable() { - @Override - public void onError(String error, String text) { - needHideProgress(); - } - }); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(phoneField ? LocaleController.getString("PassportDeletePhoneAlert", R.string.PassportDeletePhoneAlert) : LocaleController.getString("PassportDeleteEmailAlert", R.string.PassportDeleteEmailAlert)); - showDialog(builder.create()); - return; - } - } } - openTypeActivity(type, documentsType, documentTypes); } + openTypeActivity(requiredType, documentsType, documentRequiredTypes, documentOnly); }); - typesViews.put(type, view); + typesViews.put(requiredType, view); String text = null; String json = null; String documentJson = null; - typesValues.put(type, new HashMap()); + typesValues.put(requiredType, new HashMap<>()); - TLRPC.TL_secureValue value = getValueByType(type, false); + TLRPC.TL_secureValue value = getValueByType(requiredType, false); if (value != null) { if (value.plain_data instanceof TLRPC.TL_securePlainEmail) { text = ((TLRPC.TL_securePlainEmail) value.plain_data).email; @@ -5039,25 +5952,30 @@ public class PassportActivity extends BaseFragment implements NotificationCenter json = decryptData(value.data.data, decryptValueSecret(value.data.secret, value.data.data_hash), value.data.data_hash); } } - TLRPC.SecureValueType documentsType = null; - if (documentTypes != null && !documentTypes.isEmpty()) { - for (int a = 0, count = documentTypes.size(); a < count; a++) { - TLRPC.SecureValueType documentType = documentTypes.get(a); - TLRPC.TL_secureValue documentValue = getValueByType(documentType, false); - if (documentValue != null) { - if (documentValue.data != null) { - documentJson = decryptData(documentValue.data.data, decryptValueSecret(documentValue.data.secret, documentValue.data.data_hash), documentValue.data.data_hash); + TLRPC.TL_secureRequiredType documentsType = null; + if (documentRequiredTypes != null && !documentRequiredTypes.isEmpty()) { + boolean found = false; + for (int a = 0, count = documentRequiredTypes.size(); a < count; a++) { + TLRPC.TL_secureRequiredType documentType = documentRequiredTypes.get(a); + typesValues.put(documentType, new HashMap<>()); + documentsToTypesLink.put(documentType, requiredType); + if (!found) { + TLRPC.TL_secureValue documentValue = getValueByType(documentType, false); + if (documentValue != null) { + if (documentValue.data != null) { + documentJson = decryptData(documentValue.data.data, decryptValueSecret(documentValue.data.secret, documentValue.data.data_hash), documentValue.data.data_hash); + } + documentsType = documentType; + found = true; } - documentsType = documentType; - break; } } if (documentsType == null) { - documentsType = documentTypes.get(0); + documentsType = documentRequiredTypes.get(0); } } - setTypeValue(type, text, json, documentsType, documentJson); + setTypeValue(requiredType, text, json, documentsType, documentJson, documentOnly, availableDocumentTypesCount); return view; } @@ -5179,7 +6097,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return new String(decryptedData, dataOffset, decryptedData.length - dataOffset); } - private boolean checkSecret(byte[] secret, Long id) { + public static boolean checkSecret(byte[] secret, Long id) { if (secret == null || secret.length != 32) { return false; } @@ -5355,29 +6273,21 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - HashMap values = new HashMap<>(); - values.put("phone", phone); - PassportActivity activity = new PassportActivity(TYPE_PHONE_VERIFICATION, currentForm, currentPassword, currentType, null, null, null, values); - activity.currentAccount = currentAccount; - activity.saltedPassword = saltedPassword; - activity.secureSecret = secureSecret; - activity.delegate = delegate; - activity.currentPhoneVerification = (TLRPC.TL_auth_sentCode) response; - presentFragment(activity, true); - } else { - AlertsCreator.processError(currentAccount, error, PassportActivity.this, req, phone); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + HashMap values = new HashMap<>(); + values.put("phone", phone); + PassportActivity activity = new PassportActivity(TYPE_PHONE_VERIFICATION, currentForm, currentPassword, currentType, null, null, null, values, null); + activity.currentAccount = currentAccount; + activity.saltedPassword = saltedPassword; + activity.secureSecret = secureSecret; + activity.delegate = delegate; + activity.currentPhoneVerification = (TLRPC.TL_auth_sentCode) response; + presentFragment(activity, true); + } else { + AlertsCreator.processError(currentAccount, error, PassportActivity.this, req, phone); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } private void updatePasswordInterface() { @@ -5395,7 +6305,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter passwordInfoRequestTextView.setVisibility(View.GONE); passwordRequestTextView.setVisibility(View.GONE); emptyView.setVisibility(View.VISIBLE); - } else if (currentPassword instanceof TLRPC.TL_account_noPassword) { + } else if (!currentPassword.has_password) { passwordRequestTextView.setVisibility(View.VISIBLE); noPasswordImageView.setVisibility(View.VISIBLE); @@ -5550,9 +6460,20 @@ public class PassportActivity extends BaseFragment implements NotificationCenter cell.updateButtonState(true); } } - errorsValues.remove("files_all"); - if (bottomCell != null && !TextUtils.isEmpty(noAllDocumentsErrorText)) { - bottomCell.setText(noAllDocumentsErrorText); + if (errorsValues != null && errorsValues.containsKey("error_document_all")) { + errorsValues.remove("error_document_all"); + checkTopErrorCell(false); + } + if (document.type == UPLOADING_TYPE_DOCUMENTS) { + if (bottomCell != null && !TextUtils.isEmpty(noAllDocumentsErrorText)) { + bottomCell.setText(noAllDocumentsErrorText); + } + errorsValues.remove("files_all"); + } else if (document.type == UPLOADING_TYPE_TRANSLATION) { + if (bottomCellTranslation != null && !TextUtils.isEmpty(noAllTranslationErrorText)) { + bottomCellTranslation.setText(noAllTranslationErrorText); + } + errorsValues.remove("translation_all"); } } } else if (id == NotificationCenter.FileDidFailUpload) { @@ -5564,11 +6485,14 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } if (args[6] == null) { currentPassword = new TLRPC.TL_account_password(); - currentPassword.current_salt = (byte[]) args[1]; - currentPassword.new_secure_salt = (byte[]) args[2]; + currentPassword.current_algo = (TLRPC.PasswordKdfAlgo) args[1]; + currentPassword.new_secure_algo = (TLRPC.SecurePasswordKdfAlgo) args[2]; currentPassword.secure_random = (byte[]) args[3]; currentPassword.has_recovery = !TextUtils.isEmpty((String) args[4]); currentPassword.hint = (String) args[5]; + currentPassword.srp_id = -1; + currentPassword.srp_B = new byte[256]; + Utilities.random.nextBytes(currentPassword.srp_B); if (inputFields[FIELD_PASSWORD] != null && inputFields[FIELD_PASSWORD].length() > 0) { usingSavedPassword = 2; @@ -5587,12 +6511,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter @Override public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (presentAfterAnimation != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - presentFragment(presentAfterAnimation, true); - presentAfterAnimation = null; - } + AndroidUtilities.runOnUIThread(() -> { + presentFragment(presentAfterAnimation, true); + presentAfterAnimation = null; }); } if (currentActivityType == TYPE_PASSWORD) { @@ -5670,17 +6591,13 @@ public class PassportActivity extends BaseFragment implements NotificationCenter AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("PermissionNoAudioVideo", R.string.PermissionNoAudioVideo)); - builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { - @TargetApi(Build.VERSION_CODES.GINGERBREAD) - @Override - public void onClick(DialogInterface dialog, int which) { - try { - Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e(e); - } + builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e(e); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); @@ -5849,7 +6766,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } createChatAttachView(); chatAttachAlert.setOpenWithFrontFaceCamera(uploadingFileType == UPLOADING_TYPE_SELFIE); - chatAttachAlert.setMaxSelectedPhotos(uploadingFileType == UPLOADING_TYPE_DOCUMENTS ? 20 - documents.size() : 1); + chatAttachAlert.setMaxSelectedPhotos(getMaxSelectedDocuments()); chatAttachAlert.loadGalleryPhotos(); if (Build.VERSION.SDK_INT == 21 || Build.VERSION.SDK_INT == 22) { AndroidUtilities.hideKeyboard(fragmentView.findFocus()); @@ -5923,6 +6840,16 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } + private int getMaxSelectedDocuments() { + if (uploadingFileType == UPLOADING_TYPE_DOCUMENTS) { + return 20 - documents.size(); + } else if (uploadingFileType == UPLOADING_TYPE_TRANSLATION) { + return 20 - translationDocuments.size(); + } else { + return 1; + } + } + private void processSelectedAttach(int which) { if (which == attach_photo) { if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { @@ -5953,7 +6880,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(false, false, false, null); fragment.setCurrentAccount(currentAccount); - fragment.setMaxSelectedPhotos(uploadingFileType == UPLOADING_TYPE_DOCUMENTS ? 20 - documents.size() : 1); + fragment.setMaxSelectedPhotos(getMaxSelectedDocuments()); fragment.setAllowSearchImages(false); fragment.setDelegate(new PhotoAlbumPickerActivity.PhotoAlbumPickerActivityDelegate() { @Override @@ -5981,7 +6908,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter DocumentSelectActivity fragment = new DocumentSelectActivity(); fragment.setCurrentAccount(currentAccount); fragment.setCanSelectOnlyImageFiles(true); - fragment.setMaxSelectedFiles(uploadingFileType == UPLOADING_TYPE_DOCUMENTS ? 20 - documents.size() : 1); + fragment.setMaxSelectedFiles(getMaxSelectedDocuments()); fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { @Override public void didSelectFiles(DocumentSelectActivity activity, ArrayList files) { @@ -6025,12 +6952,26 @@ public class PassportActivity extends BaseFragment implements NotificationCenter for (int a = 0; a < inputFields.length; a++) { values.append(inputFields[a].getText()).append(","); } + if (inputExtraFields != null) { + for (int a = 0; a < inputExtraFields.length; a++) { + values.append(inputExtraFields[a].getText()).append(","); + } + } for (int a = 0, count = documents.size(); a < count; a++) { values.append(documents.get(a).secureFile.id); } + if (frontDocument != null) { + values.append(frontDocument.secureFile.id); + } + if (reverseDocument != null) { + values.append(reverseDocument.secureFile.id); + } if (selfieDocument != null) { values.append(selfieDocument.secureFile.id); } + for (int a = 0, count = translationDocuments.size(); a < count; a++) { + values.append(translationDocuments.get(a).secureFile.id); + } return values.toString(); } @@ -6043,12 +6984,7 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return false; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finishFragment(); - } - }); + builder.setPositiveButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialog, which) -> finishFragment()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setTitle(LocaleController.getString("DiscardChanges", R.string.DiscardChanges)); builder.setMessage(LocaleController.getString("PassportDiscardChanges", R.string.PassportDiscardChanges)); @@ -6061,9 +6997,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter return; } final boolean needRecoginze; - if (uploadingFileType == UPLOADING_TYPE_SELFIE) { + if (uploadingFileType == UPLOADING_TYPE_SELFIE || uploadingFileType == UPLOADING_TYPE_TRANSLATION) { needRecoginze = false; - } else if (currentType instanceof TLRPC.TL_secureValueTypePersonalDetails) { + } else if (currentType.type instanceof TLRPC.TL_secureValueTypePersonalDetails) { boolean allFieldsAreEmpty = true; for (int a = 0; a < inputFields.length; a++) { if (a == FIELD_CITIZENSHIP || a == FIELD_EXPIRE || a == FIELD_GENDER || a == FIELD_RESIDENCE) { @@ -6079,178 +7015,177 @@ public class PassportActivity extends BaseFragment implements NotificationCenter needRecoginze = false; } final int type = uploadingFileType; - Utilities.globalQueue.postRunnable(new Runnable() { - @Override - public void run() { - boolean didRecognizeSuccessfully = false; - for (int a = 0, count = Math.min(uploadingFileType == UPLOADING_TYPE_DOCUMENTS ? 20 : 1, photos.size()); a < count; a++) { - SendMessagesHelper.SendingMediaInfo info = photos.get(a); - Bitmap bitmap = ImageLoader.loadBitmap(info.path, info.uri, 2048, 2048, false); - if (bitmap == null) { - continue; - } - TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, 2048, 2048, 89, false, 320, 320); - if (size == null) { - continue; - } - TLRPC.TL_secureFile secureFile = new TLRPC.TL_secureFile(); - secureFile.dc_id = (int) size.location.volume_id; - secureFile.id = size.location.local_id; - secureFile.date = (int) (System.currentTimeMillis() / 1000); - - final SecureDocument document = delegate.saveFile(secureFile); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (uploadingFileType == UPLOADING_TYPE_SELFIE) { - if (selfieDocument != null) { - SecureDocumentCell cell = documentsCells.remove(selfieDocument); - if (cell != null) { - selfieLayout.removeView(cell); - } - selfieDocument = null; - } - } else if (uploadingFileType == UPLOADING_TYPE_FRONT) { - if (frontDocument != null) { - SecureDocumentCell cell = documentsCells.remove(frontDocument); - if (cell != null) { - frontLayout.removeView(cell); - } - frontDocument = null; - } - } else if (uploadingFileType == UPLOADING_TYPE_REVERSE) { - if (reverseDocument != null) { - SecureDocumentCell cell = documentsCells.remove(reverseDocument); - if (cell != null) { - reverseLayout.removeView(cell); - } - reverseDocument = null; - } - } else if (uploadingFileType == UPLOADING_TYPE_DOCUMENTS) { - if (documents.size() >= 20) { - return; - } - } - uploadingDocuments.put(document.path, document); - doneItem.setEnabled(false); - doneItem.setAlpha(0.5f); - FileLoader.getInstance(currentAccount).uploadFile(document.path, false, true, ConnectionsManager.FileTypePhoto); - addDocumentView(document, type); - updateUploadText(type); - } - }); - - if (needRecoginze && !didRecognizeSuccessfully) { - try { - final MrzRecognizer.Result result = MrzRecognizer.recognize(bitmap, currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense); - if (result != null) { - didRecognizeSuccessfully = true; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (result.type == MrzRecognizer.Result.TYPE_ID) { - if (!(currentDocumentsType instanceof TLRPC.TL_secureValueTypeIdentityCard)) { - for (int a = 0, count = availableDocumentTypes.size(); a < count; a++) { - TLRPC.SecureValueType type = availableDocumentTypes.get(a); - if (type instanceof TLRPC.TL_secureValueTypeIdentityCard) { - currentDocumentsType = type; - updateInterfaceStringsForDocumentType(); - break; - } - } - } - } else if (result.type == MrzRecognizer.Result.TYPE_PASSPORT) { - if (!(currentDocumentsType instanceof TLRPC.TL_secureValueTypePassport)) { - for (int a = 0, count = availableDocumentTypes.size(); a < count; a++) { - TLRPC.SecureValueType type = availableDocumentTypes.get(a); - if (type instanceof TLRPC.TL_secureValueTypePassport) { - currentDocumentsType = type; - updateInterfaceStringsForDocumentType(); - break; - } - } - } - } else if (result.type == MrzRecognizer.Result.TYPE_INTERNAL_PASSPORT) { - if (!(currentDocumentsType instanceof TLRPC.TL_secureValueTypeInternalPassport)) { - for (int a = 0, count = availableDocumentTypes.size(); a < count; a++) { - TLRPC.SecureValueType type = availableDocumentTypes.get(a); - if (type instanceof TLRPC.TL_secureValueTypeInternalPassport) { - currentDocumentsType = type; - updateInterfaceStringsForDocumentType(); - break; - } - } - } - } else if (result.type == MrzRecognizer.Result.TYPE_DRIVER_LICENSE) { - if (!(currentDocumentsType instanceof TLRPC.TL_secureValueTypeDriverLicense)) { - for (int a = 0, count = availableDocumentTypes.size(); a < count; a++) { - TLRPC.SecureValueType type = availableDocumentTypes.get(a); - if (type instanceof TLRPC.TL_secureValueTypeDriverLicense) { - currentDocumentsType = type; - updateInterfaceStringsForDocumentType(); - break; - } - } - } - } - if (!TextUtils.isEmpty(result.firstName)) { - inputFields[FIELD_NAME].setText(result.firstName); - } - if (!TextUtils.isEmpty(result.lastName)) { - inputFields[FIELD_SURNAME].setText(result.lastName); - } - if (!TextUtils.isEmpty(result.number)) { - inputFields[FIELD_CARDNUMBER].setText(result.number); - } - if (result.gender != MrzRecognizer.Result.GENDER_UNKNOWN) { - switch (result.gender) { - case MrzRecognizer.Result.GENDER_MALE: - currentGender = "male"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); - break; - case MrzRecognizer.Result.GENDER_FEMALE: - currentGender = "female"; - inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); - break; - } - } - if (!TextUtils.isEmpty(result.nationality)) { - currentCitizeship = result.nationality; - String country = languageMap.get(currentCitizeship); - if (country != null) { - inputFields[FIELD_CITIZENSHIP].setText(country); - } - } - if (!TextUtils.isEmpty(result.issuingCountry)) { - currentResidence = result.issuingCountry; - String country = languageMap.get(currentResidence); - if (country != null) { - inputFields[FIELD_RESIDENCE].setText(country); - } - } - if (result.birthDay > 0 && result.birthMonth > 0 && result.birthYear > 0) { - inputFields[FIELD_BIRTHDAY].setText(String.format(Locale.US, "%02d.%02d.%d", result.birthDay, result.birthMonth, result.birthYear)); - } - if (result.expiryDay > 0 && result.expiryMonth > 0 && result.expiryYear > 0) { - currentExpireDate[0] = result.expiryYear; - currentExpireDate[1] = result.expiryMonth; - currentExpireDate[2] = result.expiryDay; - inputFields[FIELD_EXPIRE].setText(String.format(Locale.US, "%02d.%02d.%d", result.expiryDay, result.expiryMonth, result.expiryYear)); - } else { - currentExpireDate[0] = currentExpireDate[1] = currentExpireDate[2] = 0; - inputFields[FIELD_EXPIRE].setText(LocaleController.getString("PassportNoExpireDate", R.string.PassportNoExpireDate)); - } - } - }); - } - } catch (Throwable e) { - FileLog.e(e); - } - } - + Utilities.globalQueue.postRunnable(() -> { + boolean didRecognizeSuccessfully = false; + for (int a = 0, count = Math.min(uploadingFileType == UPLOADING_TYPE_DOCUMENTS || uploadingFileType == UPLOADING_TYPE_TRANSLATION ? 20 : 1, photos.size()); a < count; a++) { + SendMessagesHelper.SendingMediaInfo info = photos.get(a); + Bitmap bitmap = ImageLoader.loadBitmap(info.path, info.uri, 2048, 2048, false); + if (bitmap == null) { + continue; } - SharedConfig.saveConfig(); + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, 2048, 2048, 89, false, 320, 320); + if (size == null) { + continue; + } + TLRPC.TL_secureFile secureFile = new TLRPC.TL_secureFile(); + secureFile.dc_id = (int) size.location.volume_id; + secureFile.id = size.location.local_id; + secureFile.date = (int) (System.currentTimeMillis() / 1000); + + final SecureDocument document = delegate.saveFile(secureFile); + document.type = type; + AndroidUtilities.runOnUIThread(() -> { + if (uploadingFileType == UPLOADING_TYPE_SELFIE) { + if (selfieDocument != null) { + SecureDocumentCell cell = documentsCells.remove(selfieDocument); + if (cell != null) { + selfieLayout.removeView(cell); + } + selfieDocument = null; + } + } else if (uploadingFileType == UPLOADING_TYPE_TRANSLATION) { + if (translationDocuments.size() >= 20) { + return; + } + } else if (uploadingFileType == UPLOADING_TYPE_FRONT) { + if (frontDocument != null) { + SecureDocumentCell cell = documentsCells.remove(frontDocument); + if (cell != null) { + frontLayout.removeView(cell); + } + frontDocument = null; + } + } else if (uploadingFileType == UPLOADING_TYPE_REVERSE) { + if (reverseDocument != null) { + SecureDocumentCell cell = documentsCells.remove(reverseDocument); + if (cell != null) { + reverseLayout.removeView(cell); + } + reverseDocument = null; + } + } else if (uploadingFileType == UPLOADING_TYPE_DOCUMENTS) { + if (documents.size() >= 20) { + return; + } + } + uploadingDocuments.put(document.path, document); + doneItem.setEnabled(false); + doneItem.setAlpha(0.5f); + FileLoader.getInstance(currentAccount).uploadFile(document.path, false, true, ConnectionsManager.FileTypePhoto); + addDocumentView(document, type); + updateUploadText(type); + }); + + if (needRecoginze && !didRecognizeSuccessfully) { + try { + final MrzRecognizer.Result result = MrzRecognizer.recognize(bitmap, currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense); + if (result != null) { + didRecognizeSuccessfully = true; + AndroidUtilities.runOnUIThread(() -> { + if (result.type == MrzRecognizer.Result.TYPE_ID) { + if (!(currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeIdentityCard)) { + for (int a1 = 0, count1 = availableDocumentTypes.size(); a1 < count1; a1++) { + TLRPC.TL_secureRequiredType requiredType = availableDocumentTypes.get(a1); + if (requiredType.type instanceof TLRPC.TL_secureValueTypeIdentityCard) { + currentDocumentsType = requiredType; + updateInterfaceStringsForDocumentType(); + break; + } + } + } + } else if (result.type == MrzRecognizer.Result.TYPE_PASSPORT) { + if (!(currentDocumentsType.type instanceof TLRPC.TL_secureValueTypePassport)) { + for (int a1 = 0, count1 = availableDocumentTypes.size(); a1 < count1; a1++) { + TLRPC.TL_secureRequiredType requiredType = availableDocumentTypes.get(a1); + if (requiredType.type instanceof TLRPC.TL_secureValueTypePassport) { + currentDocumentsType = requiredType; + updateInterfaceStringsForDocumentType(); + break; + } + } + } + } else if (result.type == MrzRecognizer.Result.TYPE_INTERNAL_PASSPORT) { + if (!(currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeInternalPassport)) { + for (int a1 = 0, count1 = availableDocumentTypes.size(); a1 < count1; a1++) { + TLRPC.TL_secureRequiredType requiredType = availableDocumentTypes.get(a1); + if (requiredType.type instanceof TLRPC.TL_secureValueTypeInternalPassport) { + currentDocumentsType = requiredType; + updateInterfaceStringsForDocumentType(); + break; + } + } + } + } else if (result.type == MrzRecognizer.Result.TYPE_DRIVER_LICENSE) { + if (!(currentDocumentsType.type instanceof TLRPC.TL_secureValueTypeDriverLicense)) { + for (int a1 = 0, count1 = availableDocumentTypes.size(); a1 < count1; a1++) { + TLRPC.TL_secureRequiredType requiredType = availableDocumentTypes.get(a1); + if (requiredType.type instanceof TLRPC.TL_secureValueTypeDriverLicense) { + currentDocumentsType = requiredType; + updateInterfaceStringsForDocumentType(); + break; + } + } + } + } + if (!TextUtils.isEmpty(result.firstName)) { + inputFields[FIELD_NAME].setText(result.firstName); + } + if (!TextUtils.isEmpty(result.middleName)) { + inputFields[FIELD_MIDNAME].setText(result.middleName); + } + if (!TextUtils.isEmpty(result.lastName)) { + inputFields[FIELD_SURNAME].setText(result.lastName); + } + if (!TextUtils.isEmpty(result.number)) { + inputFields[FIELD_CARDNUMBER].setText(result.number); + } + if (result.gender != MrzRecognizer.Result.GENDER_UNKNOWN) { + switch (result.gender) { + case MrzRecognizer.Result.GENDER_MALE: + currentGender = "male"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportMale", R.string.PassportMale)); + break; + case MrzRecognizer.Result.GENDER_FEMALE: + currentGender = "female"; + inputFields[FIELD_GENDER].setText(LocaleController.getString("PassportFemale", R.string.PassportFemale)); + break; + } + } + if (!TextUtils.isEmpty(result.nationality)) { + currentCitizeship = result.nationality; + String country = languageMap.get(currentCitizeship); + if (country != null) { + inputFields[FIELD_CITIZENSHIP].setText(country); + } + } + if (!TextUtils.isEmpty(result.issuingCountry)) { + currentResidence = result.issuingCountry; + String country = languageMap.get(currentResidence); + if (country != null) { + inputFields[FIELD_RESIDENCE].setText(country); + } + } + if (result.birthDay > 0 && result.birthMonth > 0 && result.birthYear > 0) { + inputFields[FIELD_BIRTHDAY].setText(String.format(Locale.US, "%02d.%02d.%d", result.birthDay, result.birthMonth, result.birthYear)); + } + if (result.expiryDay > 0 && result.expiryMonth > 0 && result.expiryYear > 0) { + currentExpireDate[0] = result.expiryYear; + currentExpireDate[1] = result.expiryMonth; + currentExpireDate[2] = result.expiryDay; + inputFields[FIELD_EXPIRE].setText(String.format(Locale.US, "%02d.%02d.%d", result.expiryDay, result.expiryMonth, result.expiryYear)); + } else { + currentExpireDate[0] = currentExpireDate[1] = currentExpireDate[2] = 0; + inputFields[FIELD_EXPIRE].setText(LocaleController.getString("PassportNoExpireDate", R.string.PassportNoExpireDate)); + } + }); + } + } catch (Throwable e) { + FileLog.e(e); + } + } + } + SharedConfig.saveConfig(); }); } @@ -6375,15 +7310,12 @@ public class PassportActivity extends BaseFragment implements NotificationCenter } } }); - codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - onNextPressed(); - return true; - } - return false; + codeField.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + onNextPressed(); + return true; } + return false; }); if (verificationType == 3) { codeField.setEnabled(false); @@ -6411,28 +7343,25 @@ public class PassportActivity extends BaseFragment implements NotificationCenter problemText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); problemText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(12)); addView(problemText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 20, 0, 0)); - problemText.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (nextPressed) { - return; - } - if (nextType != 0 && nextType != 4) { - resendCode(); - } else { - try { - PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); + problemText.setOnClickListener(v -> { + if (nextPressed) { + return; + } + if (nextType != 0 && nextType != 4) { + resendCode(); + } else { + try { + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); - Intent mailer = new Intent(Intent.ACTION_SEND); - mailer.setType("message/rfc822"); - mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); - mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + phone); - mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + phone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); - getContext().startActivity(Intent.createChooser(mailer, "Send email...")); - } catch (Exception e) { - AlertsCreator.showSimpleAlert(PassportActivity.this, LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); - } + Intent mailer = new Intent(Intent.ACTION_SEND); + mailer.setType("message/rfc822"); + mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); + mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + phone); + mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + phone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); + getContext().startActivity(Intent.createChooser(mailer, "Send email...")); + } catch (Exception e) { + AlertsCreator.showSimpleAlert(PassportActivity.this, LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); } } }); @@ -6448,32 +7377,21 @@ public class PassportActivity extends BaseFragment implements NotificationCenter final TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = phone; req.phone_code_hash = phoneHash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - nextPressed = false; - if (error == null) { - fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response, true); - } else { - AlertDialog dialog = (AlertDialog) AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); - if (dialog != null && error.text.contains("PHONE_CODE_EXPIRED")) { - dialog.setPositiveButtonListener(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - onBackPressed(); - finishFragment(); - } - }); - } - } - needHideProgress(); - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + nextPressed = false; + if (error == null) { + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response, true); + } else { + AlertDialog dialog = (AlertDialog) AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); + if (dialog != null && error.text.contains("PHONE_CODE_EXPIRED")) { + dialog.setPositiveButtonListener((dialog1, which) -> { + onBackPressed(); + finishFragment(); + }); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + needHideProgress(); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } @Override @@ -6577,13 +7495,10 @@ public class PassportActivity extends BaseFragment implements NotificationCenter double diff = currentTime - lastCodeTime; codeTime -= diff; lastCodeTime = currentTime; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (codeTime <= 1000) { - problemText.setVisibility(VISIBLE); - destroyCodeTimer(); - } + AndroidUtilities.runOnUIThread(() -> { + if (codeTime <= 1000) { + problemText.setVisibility(VISIBLE); + destroyCodeTimer(); } }); } @@ -6650,17 +7565,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = phone; req.phone_code_hash = phoneHash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - if (error != null && error.text != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - lastError = error.text; - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error != null && error.text != null) { + AndroidUtilities.runOnUIThread(() -> lastError = error.text); } }, ConnectionsManager.RequestFlagFailOnServerErrors); } else if (nextType == 3) { @@ -6711,44 +7618,31 @@ public class PassportActivity extends BaseFragment implements NotificationCenter req.phone_code_hash = phoneHash; destroyTimer(); needShowProgress(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - nextPressed = false; - if (error == null) { - destroyTimer(); - destroyCodeTimer(); - delegate.saveValue(currentType, currentValues.get("phone"), null, null, null, null, null, null, null, new Runnable() { - @Override - public void run() { - finishFragment(); - } - }, null); - } else { - lastError = error.text; - if (verificationType == 3 && (nextType == 4 || nextType == 2) || verificationType == 2 && (nextType == 4 || nextType == 3)) { - createTimer(); - } - if (verificationType == 2) { - AndroidUtilities.setWaitingForSms(true); - NotificationCenter.getGlobalInstance().addObserver(PhoneConfirmationView.this, NotificationCenter.didReceiveSmsCode); - } else if (verificationType == 3) { - AndroidUtilities.setWaitingForCall(true); - NotificationCenter.getGlobalInstance().addObserver(PhoneConfirmationView.this, NotificationCenter.didReceiveCall); - } - waitingForEvent = true; - if (verificationType != 3) { - AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); - } - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + nextPressed = false; + if (error == null) { + destroyTimer(); + destroyCodeTimer(); + delegate.saveValue(currentType, currentValues.get("phone"), null, null, null, null, null, null, null, null, PassportActivity.this::finishFragment, null); + } else { + lastError = error.text; + if (verificationType == 3 && (nextType == 4 || nextType == 2) || verificationType == 2 && (nextType == 4 || nextType == 3)) { + createTimer(); + } + if (verificationType == 2) { + AndroidUtilities.setWaitingForSms(true); + NotificationCenter.getGlobalInstance().addObserver(PhoneConfirmationView.this, NotificationCenter.didReceiveSmsCode); + } else if (verificationType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getGlobalInstance().addObserver(PhoneConfirmationView.this, NotificationCenter.didReceiveCall); + } + waitingForEvent = true; + if (verificationType != 3) { + AlertsCreator.processError(currentAccount, error, PassportActivity.this, req); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } @Override @@ -6756,11 +7650,8 @@ public class PassportActivity extends BaseFragment implements NotificationCenter TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); req.phone_number = phone; req.phone_code_hash = phoneHash; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }, ConnectionsManager.RequestFlagFailOnServerErrors); destroyTimer(); @@ -6838,6 +7729,9 @@ public class PassportActivity extends BaseFragment implements NotificationCenter arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); arrayList.add(new ThemeDescription(extraBackgroundView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite)); + if (extraBackgroundView2 != null) { + arrayList.add(new ThemeDescription(extraBackgroundView2, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite)); + } for (int a = 0; a < dividers.size(); a++) { arrayList.add(new ThemeDescription(dividers.get(a), ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_divider)); @@ -6890,6 +7784,18 @@ public class PassportActivity extends BaseFragment implements NotificationCenter arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteRedText3)); } + if (inputExtraFields != null) { + for (int a = 0; a < inputExtraFields.length; a++) { + arrayList.add(new ThemeDescription((View) inputExtraFields[a].getParent(), ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_windowBackgroundWhiteInputField)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_DRAWABLESELECTEDSTATE, null, null, null, null, Theme.key_windowBackgroundWhiteInputFieldActivated)); + arrayList.add(new ThemeDescription(inputExtraFields[a], ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteRedText3)); + } + } + arrayList.add(new ThemeDescription(emptyView, ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_progressCircle)); arrayList.add(new ThemeDescription(noPasswordImageView, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_chat_messagePanelIcons)); arrayList.add(new ThemeDescription(noPasswordTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteGrayText4)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index f42c5967c..dcbeb139f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -19,14 +19,12 @@ import android.app.Dialog; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Typeface; import android.net.Uri; import android.os.Build; -import android.os.Bundle; import android.os.Vibrator; import android.telephony.TelephonyManager; import android.text.Editable; @@ -41,7 +39,6 @@ import android.text.method.PasswordTransformationMethod; import android.text.style.ClickableSpan; import android.util.TypedValue; import android.view.Gravity; -import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -61,10 +58,7 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.api.BooleanResult; import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.wallet.Cart; import com.google.android.gms.wallet.FullWallet; import com.google.android.gms.wallet.FullWalletRequest; @@ -101,6 +95,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SRPHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -135,7 +130,6 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Locale; @@ -203,7 +197,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private PaymentInfoCell paymentInfoCell; private TextDetailSettingsCell detailSettingsCell[] = new TextDetailSettingsCell[7]; - private TLRPC.account_Password currentPassword; + private TLRPC.TL_account_password currentPassword; private boolean waitingForEmail; private Runnable shortPollRunnable; private boolean loadingPasswordInfo; @@ -256,30 +250,27 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private interface PaymentFormActivityDelegate { boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsAndroidPay androidPay); void onFragmentDestroyed(); - void currentPasswordUpdated(TLRPC.account_Password password); + void currentPasswordUpdated(TLRPC.TL_account_password password); } private class TelegramWebviewProxy { @JavascriptInterface public void postEvent(final String eventName, final String eventData) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (getParentActivity() == null) { - return; - } - if (eventName.equals("payment_form_submit")) { - try { - JSONObject jsonObject = new JSONObject(eventData); - JSONObject response = jsonObject.getJSONObject("credentials"); - paymentJson = response.toString(); - cardName = jsonObject.getString("title"); - } catch (Throwable e) { - paymentJson = eventData; - FileLog.e(e); - } - goToNextStep(); + AndroidUtilities.runOnUIThread(() -> { + if (getParentActivity() == null) { + return; + } + if (eventName.equals("payment_form_submit")) { + try { + JSONObject jsonObject = new JSONObject(eventData); + JSONObject response = jsonObject.getJSONObject("credentials"); + paymentJson = response.toString(); + cardName = jsonObject.getString("title"); + } catch (Throwable e) { + paymentJson = eventData; + FileLog.e(e); } + goToNextStep(); } }); } @@ -347,8 +338,8 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen init(form, message, step, validatedRequestedInfo, shipping, tokenJson, card, request, saveCard, androidPay); } - private void setCurrentPassword(TLRPC.account_Password password) { - if (password instanceof TLRPC.TL_account_password) { + private void setCurrentPassword(TLRPC.TL_account_password password) { + if (password.has_password) { if (getParentActivity() == null) { return; } @@ -356,7 +347,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } else { currentPassword = password; if (currentPassword != null) { - waitingForEmail = currentPassword.email_unconfirmed_pattern.length() > 0; + waitingForEmail = !TextUtils.isEmpty(currentPassword.email_unconfirmed_pattern); } updatePasswordFields(); } @@ -537,12 +528,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen FileLog.e(e); } - Collections.sort(countriesArray, new Comparator() { - @Override - public int compare(String lhs, String rhs) { - return lhs.compareTo(rhs); - } - }); + Collections.sort(countriesArray, String::compareTo); inputFields = new EditTextBoldCursor[FIELDS_COUNT_ADDRESS]; for (int a = 0; a < FIELDS_COUNT_ADDRESS; a++) { @@ -603,25 +589,19 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen inputFields[a].setCursorSize(AndroidUtilities.dp(20)); inputFields[a].setCursorWidth(1.5f); if (a == FIELD_COUNTRY) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - CountrySelectActivity fragment = new CountrySelectActivity(false); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - inputFields[FIELD_COUNTRY].setText(name); - countryName = shortName; - } - }); - presentFragment(fragment); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + CountrySelectActivity fragment = new CountrySelectActivity(false); + fragment.setCountrySelectActivityDelegate((name, shortName) -> { + inputFields[FIELD_COUNTRY].setText(name); + countryName = shortName; + }); + presentFragment(fragment); + } + return true; }); inputFields[a].setInputType(0); } @@ -856,25 +836,22 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); } - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - int num = (Integer) textView.getTag(); - while (num + 1 < inputFields.length) { - num++; - if (num != FIELD_COUNTRY && ((View) inputFields[num].getParent()).getVisibility() == View.VISIBLE) { - inputFields[num].requestFocus(); - break; - } + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + while (num + 1 < inputFields.length) { + num++; + if (num != FIELD_COUNTRY && ((View) inputFields[num].getParent()).getVisibility() == View.VISIBLE) { + inputFields[num].requestFocus(); + break; } - return true; - } else if (i == EditorInfo.IME_ACTION_DONE) { - doneItem.performClick(); - return true; } - return false; + return true; + } else if (i == EditorInfo.IME_ACTION_DONE) { + doneItem.performClick(); + return true; } + return false; }); if (a == FIELD_PHONE) { if (paymentForm.invoice.email_to_provider || paymentForm.invoice.phone_to_provider) { @@ -911,12 +888,9 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen checkCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); checkCell1.setTextAndCheck(LocaleController.getString("PaymentShippingSave", R.string.PaymentShippingSave), saveShippingInfo, false); linearLayout2.addView(checkCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - checkCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - saveShippingInfo = !saveShippingInfo; - checkCell1.setChecked(saveShippingInfo); - } + checkCell1.setOnClickListener(v -> { + saveShippingInfo = !saveShippingInfo; + checkCell1.setChecked(saveShippingInfo); }); bottomCell[0] = new TextInfoPrivacyCell(context); @@ -1074,12 +1048,9 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen checkCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); checkCell1.setTextAndCheck(LocaleController.getString("PaymentCardSavePaymentInformation", R.string.PaymentCardSavePaymentInformation), saveCardInfo, false); linearLayout2.addView(checkCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - checkCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - saveCardInfo = !saveCardInfo; - checkCell1.setChecked(saveCardInfo); - } + checkCell1.setOnClickListener(v -> { + saveCardInfo = !saveCardInfo; + checkCell1.setChecked(saveCardInfo); }); bottomCell[0] = new TextInfoPrivacyCell(context); @@ -1156,24 +1127,16 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } else if (a == FIELD_CARD) { inputFields[a].setInputType(InputType.TYPE_CLASS_NUMBER); } else if (a == FIELD_CARD_COUNTRY) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (getParentActivity() == null) { - return false; - } - if (event.getAction() == MotionEvent.ACTION_UP) { - CountrySelectActivity fragment = new CountrySelectActivity(false); - fragment.setCountrySelectActivityDelegate(new CountrySelectActivity.CountrySelectActivityDelegate() { - @Override - public void didSelectCountry(String name, String shortName) { - inputFields[FIELD_CARD_COUNTRY].setText(name); - } - }); - presentFragment(fragment); - } - return true; + inputFields[a].setOnTouchListener((v, event) -> { + if (getParentActivity() == null) { + return false; } + if (event.getAction() == MotionEvent.ACTION_UP) { + CountrySelectActivity fragment = new CountrySelectActivity(false); + fragment.setCountrySelectActivityDelegate((name, shortName) -> inputFields[FIELD_CARD_COUNTRY].setText(name)); + presentFragment(fragment); + } + return true; }); inputFields[a].setInputType(0); } else if (a == FIELD_EXPIRE_DATE) { @@ -1480,28 +1443,25 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - int num = (Integer) textView.getTag(); - while (num + 1 < inputFields.length) { + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + while (num + 1 < inputFields.length) { + num++; + if (num == FIELD_CARD_COUNTRY) { num++; - if (num == FIELD_CARD_COUNTRY) { - num++; - } - if (((View) inputFields[num].getParent()).getVisibility() == View.VISIBLE) { - inputFields[num].requestFocus(); - break; - } } - return true; - } else if (i == EditorInfo.IME_ACTION_DONE) { - doneItem.performClick(); - return true; + if (((View) inputFields[num].getParent()).getVisibility() == View.VISIBLE) { + inputFields[num].requestFocus(); + break; + } } - return false; + return true; + } else if (i == EditorInfo.IME_ACTION_DONE) { + doneItem.performClick(); + return true; } + return false; }); if (a == FIELD_CVV) { sectionCell[0] = new ShadowSectionCell(context); @@ -1514,12 +1474,9 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen checkCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); checkCell1.setTextAndCheck(LocaleController.getString("PaymentCardSavePaymentInformation", R.string.PaymentCardSavePaymentInformation), saveCardInfo, false); linearLayout2.addView(checkCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - checkCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - saveCardInfo = !saveCardInfo; - checkCell1.setChecked(saveCardInfo); - } + checkCell1.setOnClickListener(v -> { + saveCardInfo = !saveCardInfo; + checkCell1.setChecked(saveCardInfo); }); bottomCell[0] = new TextInfoPrivacyCell(context); @@ -1564,13 +1521,10 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen radioCells[a].setTag(a); radioCells[a].setBackgroundDrawable(Theme.getSelectorDrawable(true)); radioCells[a].setText(String.format("%s - %s", getTotalPriceString(shippingOption.prices), shippingOption.title), a == 0, a != count - 1); - radioCells[a].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int num = (Integer) v.getTag(); - for (int a = 0; a < radioCells.length; a++) { - radioCells[a].setChecked(num == a, true); - } + radioCells[a].setOnClickListener(v -> { + int num = (Integer) v.getTag(); + for (int a1 = 0; a1 < radioCells.length; a1++) { + radioCells[a1].setChecked(num == a1, true); } }); linearLayout2.addView(radioCells[a]); @@ -1617,12 +1571,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen inputFields[a].setCursorSize(AndroidUtilities.dp(20)); inputFields[a].setCursorWidth(1.5f); if (a == FIELD_SAVEDCARD) { - inputFields[a].setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }); + inputFields[a].setOnTouchListener((v, event) -> true); inputFields[a].setInputType(0); } else { inputFields[a].setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); @@ -1643,15 +1592,12 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE) { - doneItem.performClick(); - return true; - } - return false; + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE) { + doneItem.performClick(); + return true; } + return false; }); if (a == FIELD_SAVEDPASSWORD) { bottomCell[0] = new TextInfoPrivacyCell(context); @@ -1663,12 +1609,9 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen settingsCell1.setBackgroundDrawable(Theme.getSelectorDrawable(true)); settingsCell1.setText(LocaleController.getString("PaymentConfirmationNewCard", R.string.PaymentConfirmationNewCard), false); linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - passwordOk = false; - goToNextStep(); - } + settingsCell1.setOnClickListener(v -> { + passwordOk = false; + goToNextStep(); }); bottomCell[1] = new TextInfoPrivacyCell(context); @@ -1715,34 +1658,31 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); linearLayout2.addView(detailSettingsCell[0]); if (currentStep == 4) { - detailSettingsCell[0].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 2, requestedInfo, shippingOption, null, cardName, validateRequest, saveCardInfo, null); - activity.setDelegate(new PaymentFormActivityDelegate() { - @Override - public boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsAndroidPay androidPay) { - paymentForm.saved_credentials = null; - paymentJson = tokenJson; - saveCardInfo = saveCard; - cardName = card; - androidPayCredentials = androidPay; - detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); - return false; - } + detailSettingsCell[0].setOnClickListener(v -> { + PaymentFormActivity activity = new PaymentFormActivity(paymentForm, messageObject, 2, requestedInfo, shippingOption, null, cardName, validateRequest, saveCardInfo, null); + activity.setDelegate(new PaymentFormActivityDelegate() { + @Override + public boolean didSelectNewCard(String tokenJson, String card, boolean saveCard, TLRPC.TL_inputPaymentCredentialsAndroidPay androidPay) { + paymentForm.saved_credentials = null; + paymentJson = tokenJson; + saveCardInfo = saveCard; + cardName = card; + androidPayCredentials = androidPay; + detailSettingsCell[0].setTextAndValue(cardName, LocaleController.getString("PaymentCheckoutMethod", R.string.PaymentCheckoutMethod), true); + return false; + } - @Override - public void onFragmentDestroyed() { + @Override + public void onFragmentDestroyed() { - } + } - @Override - public void currentPasswordUpdated(TLRPC.account_Password password) { + @Override + public void currentPasswordUpdated(TLRPC.TL_account_password password) { - } - }); - presentFragment(activity); - } + } + }); + presentFragment(activity); }); } @@ -1805,30 +1745,22 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen bottomLayout = new FrameLayout(context); bottomLayout.setBackgroundDrawable(Theme.getSelectorDrawable(true)); frameLayout.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); - bottomLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (botUser != null && !botUser.verified) { - String botKey = "payment_warning_" + botUser.id; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - if (!preferences.getBoolean(botKey, false)) { - preferences.edit().putBoolean(botKey, true).commit(); - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("PaymentWarning", R.string.PaymentWarning)); - builder.setMessage(LocaleController.formatString("PaymentWarningText", R.string.PaymentWarningText, currentBotName, providerName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - showPayAlert(totalPrice); - } - }); - showDialog(builder.create()); - } else { - showPayAlert(totalPrice); - } + bottomLayout.setOnClickListener(v -> { + if (botUser != null && !botUser.verified) { + String botKey = "payment_warning_" + botUser.id; + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + if (!preferences.getBoolean(botKey, false)) { + preferences.edit().putBoolean(botKey, true).commit(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("PaymentWarning", R.string.PaymentWarning)); + builder.setMessage(LocaleController.formatString("PaymentWarningText", R.string.PaymentWarningText, currentBotName, providerName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> showPayAlert(totalPrice)); + showDialog(builder.create()); } else { showPayAlert(totalPrice); } + } else { + showPayAlert(totalPrice); } }); payTextView = new TextView(context); @@ -1924,25 +1856,17 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen settingsCell1.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); settingsCell1.setText(LocaleController.getString("AbortPassword", R.string.AbortPassword), false); linearLayout2.addView(settingsCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - settingsCell1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - String text = LocaleController.getString("TurnPasswordOffQuestion", R.string.TurnPasswordOffQuestion); - if (currentPassword.has_secure_values) { - text += "\n\n" + LocaleController.getString("TurnPasswordOffPassport", R.string.TurnPasswordOffPassport); - } - builder.setMessage(text); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - sendSavePassword(true); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + settingsCell1.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + String text = LocaleController.getString("TurnPasswordOffQuestion", R.string.TurnPasswordOffQuestion); + if (currentPassword.has_secure_values) { + text += "\n\n" + LocaleController.getString("TurnPasswordOffPassport", R.string.TurnPasswordOffPassport); } + builder.setMessage(text); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> sendSavePassword(true)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); }); inputFields = new EditTextBoldCursor[FIELDS_COUNT_PASSWORD]; @@ -2005,22 +1929,19 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen inputFields[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); container.addView(inputFields[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 17, 12, 17, 6)); - inputFields[a].setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE) { - doneItem.performClick(); - return true; - } else if (i == EditorInfo.IME_ACTION_NEXT) { - int num = (Integer) textView.getTag(); - if (num == FIELD_ENTERPASSWORD) { - inputFields[FIELD_REENTERPASSWORD].requestFocus(); - } else if (num == FIELD_REENTERPASSWORD) { - inputFields[FIELD_ENTERPASSWORDEMAIL].requestFocus(); - } + inputFields[a].setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_DONE) { + doneItem.performClick(); + return true; + } else if (i == EditorInfo.IME_ACTION_NEXT) { + int num = (Integer) textView.getTag(); + if (num == FIELD_ENTERPASSWORD) { + inputFields[FIELD_REENTERPASSWORD].requestFocus(); + } else if (num == FIELD_REENTERPASSWORD) { + inputFields[FIELD_ENTERPASSWORDEMAIL].requestFocus(); } - return false; } + return false; }); if (a == FIELD_REENTERPASSWORD) { bottomCell[0] = new TextInfoPrivacyCell(context); @@ -2064,7 +1985,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } doneItem.setVisibility(View.GONE); - bottomCell[2].setText(LocaleController.formatString("EmailPasswordConfirmText", R.string.EmailPasswordConfirmText, currentPassword.email_unconfirmed_pattern)); + bottomCell[2].setText(LocaleController.formatString("EmailPasswordConfirmText", R.string.EmailPasswordConfirmText, currentPassword.email_unconfirmed_pattern != null ? currentPassword.email_unconfirmed_pattern : "")); bottomCell[2].setVisibility(View.VISIBLE); settingsCell1.setVisibility(View.VISIBLE); bottomCell[1].setText(""); @@ -2103,45 +2024,35 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } loadingPasswordInfo = true; TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loadingPasswordInfo = false; - if (error == null) { - currentPassword = (TLRPC.account_Password) response; - if (paymentForm != null && currentPassword instanceof TLRPC.TL_account_password) { - paymentForm.password_missing = false; - paymentForm.can_save_credentials = true; - updateSavePaymentField(); - } - byte[] salt = new byte[currentPassword.new_salt.length + 8]; - Utilities.random.nextBytes(salt); - System.arraycopy(currentPassword.new_salt, 0, salt, 0, currentPassword.new_salt.length); - currentPassword.new_salt = salt; - if (passwordFragment != null) { - passwordFragment.setCurrentPassword(currentPassword); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + loadingPasswordInfo = false; + if (error == null) { + currentPassword = (TLRPC.TL_account_password) response; + if (!TwoStepVerificationActivity.canHandleCurrentPassword(currentPassword, false)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + return; + } + if (paymentForm != null && currentPassword.has_password) { + paymentForm.password_missing = false; + paymentForm.can_save_credentials = true; + updateSavePaymentField(); + } + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + if (passwordFragment != null) { + passwordFragment.setCurrentPassword(currentPassword); + } + if (!currentPassword.has_password && shortPollRunnable == null) { + shortPollRunnable = () -> { + if (shortPollRunnable == null) { + return; } - if (response instanceof TLRPC.TL_account_noPassword && shortPollRunnable == null) { - shortPollRunnable = new Runnable() { - @Override - public void run() { - if (shortPollRunnable == null) { - return; - } - loadPasswordInfo(); - shortPollRunnable = null; - } - }; - AndroidUtilities.runOnUIThread(shortPollRunnable, 5000); - } - } - }); + loadPasswordInfo(); + shortPollRunnable = null; + }; + AndroidUtilities.runOnUIThread(shortPollRunnable, 5000); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } private void showAlertWithText(String title, String text) { @@ -2156,22 +2067,16 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("PaymentTransactionReview", R.string.PaymentTransactionReview)); builder.setMessage(LocaleController.formatString("PaymentTransactionMessage", R.string.PaymentTransactionMessage, totalPrice, currentBotName, currentItemName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - setDonePressed(true); - sendData(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + setDonePressed(true); + sendData(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } private void initAndroidPay(Context context) { -// if (Build.VERSION.SDK_INT < 19) { -// return; -// } - if (Build.VERSION.SDK_INT >= 0) { + /*if (Build.VERSION.SDK_INT < 19) { return; } googleApiClient = new GoogleApiClient.Builder(context) @@ -2186,11 +2091,8 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } }) - .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { - @Override - public void onConnectionFailed(ConnectionResult connectionResult) { + .addOnConnectionFailedListener(connectionResult -> { - } }) .addApi(Wallet.API, new Wallet.WalletOptions.Builder() .setEnvironment(paymentForm.invoice.test ? WalletConstants.ENVIRONMENT_TEST : WalletConstants.ENVIRONMENT_PRODUCTION) @@ -2199,20 +2101,17 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen .build(); Wallet.Payments.isReadyToPay(googleApiClient).setResultCallback( - new ResultCallback() { - @Override - public void onResult(BooleanResult booleanResult) { - if (booleanResult.getStatus().isSuccess()) { - if (booleanResult.getValue()) { - showAndroidPay(); - } - } else { - + booleanResult -> { + if (booleanResult.getStatus().isSuccess()) { + if (booleanResult.getValue()) { + showAndroidPay(); } + } else { + } } ); - googleApiClient.connect(); + googleApiClient.connect();*/ } private String getTotalPriceString(ArrayList prices) { @@ -2517,7 +2416,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } @Override - public void currentPasswordUpdated(TLRPC.account_Password password) { + public void currentPasswordUpdated(TLRPC.TL_account_password password) { currentPassword = password; } }); @@ -2634,15 +2533,17 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private void sendSavePassword(final boolean clear) { final TLRPC.TL_account_updatePasswordSettings req = new TLRPC.TL_account_updatePasswordSettings(); final String email; + final String firstPassword; if (clear) { doneItem.setVisibility(View.VISIBLE); email = null; + firstPassword = null; req.new_settings = new TLRPC.TL_account_passwordInputSettings(); req.new_settings.flags = 2; req.new_settings.email = ""; - req.current_password_hash = new byte[0]; + req.password = new TLRPC.TL_inputCheckPasswordEmpty(); } else { - final String firstPassword = inputFields[FIELD_ENTERPASSWORD].getText().toString(); + firstPassword = inputFields[FIELD_ENTERPASSWORD].getText().toString(); if (TextUtils.isEmpty(firstPassword)) { shakeField(FIELD_ENTERPASSWORD); return; @@ -2669,24 +2570,11 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen return; } - req.current_password_hash = new byte[0]; + req.password = new TLRPC.TL_inputCheckPasswordEmpty(); req.new_settings = new TLRPC.TL_account_passwordInputSettings(); - byte[] newPasswordBytes = null; - try { - newPasswordBytes = firstPassword.getBytes("UTF-8"); - } catch (Exception e) { - FileLog.e(e); - } - - byte[] new_salt = currentPassword.new_salt; - byte[] hash = new byte[new_salt.length * 2 + newPasswordBytes.length]; - System.arraycopy(new_salt, 0, hash, 0, new_salt.length); - System.arraycopy(newPasswordBytes, 0, hash, new_salt.length, newPasswordBytes.length); - System.arraycopy(new_salt, 0, hash, hash.length - new_salt.length, new_salt.length); req.new_settings.flags |= 1; req.new_settings.hint = ""; - req.new_settings.new_password_hash = Utilities.computeSHA256(hash, 0, hash.length); - req.new_settings.new_salt = new_salt; + req.new_settings.new_algo = currentPassword.new_algo; if (email.length() > 0) { req.new_settings.flags |= 2; @@ -2694,63 +2582,86 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen } } showEditDoneProgress(true, true); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - showEditDoneProgress(true, false); - if (clear) { - currentPassword = new TLRPC.TL_account_noPassword(); - delegate.currentPasswordUpdated(currentPassword); - finishFragment(); + Utilities.globalQueue.postRunnable(() -> { + RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); + sendSavePassword(clear); + } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + showEditDoneProgress(true, false); + if (clear) { + currentPassword.has_password = false; + currentPassword.current_algo = null; + delegate.currentPasswordUpdated(currentPassword); + finishFragment(); + } else { + if (error == null && response instanceof TLRPC.TL_boolTrue) { + if (getParentActivity() == null) { + return; + } + goToNextStep(); + } else if (error != null) { + if (error.text.equals("EMAIL_UNCONFIRMED")) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + waitingForEmail = true; + currentPassword.email_unconfirmed_pattern = email; + updatePasswordFields(); + }); + builder.setMessage(LocaleController.getString("YourEmailAlmostThereText", R.string.YourEmailAlmostThereText)); + builder.setTitle(LocaleController.getString("YourEmailAlmostThere", R.string.YourEmailAlmostThere)); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); + } } else { - if (error == null && response instanceof TLRPC.TL_boolTrue) { - if (getParentActivity() == null) { - return; - } - goToNextStep(); - } else if (error != null) { - if (error.text.equals("EMAIL_UNCONFIRMED")) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - waitingForEmail = true; - currentPassword.email_unconfirmed_pattern = email; - updatePasswordFields(); - } - }); - builder.setMessage(LocaleController.getString("YourEmailAlmostThereText", R.string.YourEmailAlmostThereText)); - builder.setTitle(LocaleController.getString("YourEmailAlmostThere", R.string.YourEmailAlmostThere)); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } + if (error.text.equals("EMAIL_INVALID")) { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PasswordEmailInvalid", R.string.PasswordEmailInvalid)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); } else { - if (error.text.equals("EMAIL_INVALID")) { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PasswordEmailInvalid", R.string.PasswordEmailInvalid)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } + timeString = LocaleController.formatPluralString("Minutes", time / 60); } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); } } } - }); + } + }); + + if (!clear) { + byte[] newPasswordBytes = AndroidUtilities.getStringBytes(firstPassword); + if (currentPassword.new_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.new_algo; + req.new_settings.new_password_hash = SRPHelper.getVBytes(newPasswordBytes, algo); + if (req.new_settings.new_password_hash == null) { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "ALGO_INVALID"; + requestDelegate.run(null, error); + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error); + } + } else { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + }); } private boolean sendCardData() { @@ -2804,13 +2715,10 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen return; } paymentJson = String.format(Locale.US, "{\"type\":\"%1$s\", \"id\":\"%2$s\"}", token.getType(), token.getId()); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - goToNextStep(); - showEditDoneProgress(true, false); - setDonePressed(false); - } + AndroidUtilities.runOnUIThread(() -> { + goToNextStep(); + showEditDoneProgress(true, false); + setDonePressed(false); }); } @@ -2866,72 +2774,60 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen validateRequest.info.flags |= 8; } final TLObject req = validateRequest; - ConnectionsManager.getInstance(currentAccount).sendRequest(validateRequest, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (response instanceof TLRPC.TL_payments_validatedRequestedInfo) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - requestedInfo = (TLRPC.TL_payments_validatedRequestedInfo) response; - if (paymentForm.saved_info != null && !saveShippingInfo) { - TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); - req.info = true; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(validateRequest, (response, error) -> { + if (response instanceof TLRPC.TL_payments_validatedRequestedInfo) { + AndroidUtilities.runOnUIThread(() -> { + requestedInfo = (TLRPC.TL_payments_validatedRequestedInfo) response; + if (paymentForm.saved_info != null && !saveShippingInfo) { + TLRPC.TL_payments_clearSavedInfo req1 = new TLRPC.TL_payments_clearSavedInfo(); + req1.info = true; + ConnectionsManager.getInstance(currentAccount).sendRequest(req1, (response1, error1) -> { - } - }); - } - goToNextStep(); - setDonePressed(false); - showEditDoneProgress(true, false); + }); + } + goToNextStep(); + setDonePressed(false); + showEditDoneProgress(true, false); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + setDonePressed(false); + showEditDoneProgress(true, false); + if (error != null) { + switch (error.text) { + case "REQ_INFO_NAME_INVALID": + shakeField(FIELD_NAME); + break; + case "REQ_INFO_PHONE_INVALID": + shakeField(FIELD_PHONE); + break; + case "REQ_INFO_EMAIL_INVALID": + shakeField(FIELD_EMAIL); + break; + case "ADDRESS_COUNTRY_INVALID": + shakeField(FIELD_COUNTRY); + break; + case "ADDRESS_CITY_INVALID": + shakeField(FIELD_CITY); + break; + case "ADDRESS_POSTCODE_INVALID": + shakeField(FIELD_POSTCODE); + break; + case "ADDRESS_STATE_INVALID": + shakeField(FIELD_STATE); + break; + case "ADDRESS_STREET_LINE1_INVALID": + shakeField(FIELD_STREET1); + break; + case "ADDRESS_STREET_LINE2_INVALID": + shakeField(FIELD_STREET2); + break; + default: + AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); + break; } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - setDonePressed(false); - showEditDoneProgress(true, false); - if (error != null) { - switch (error.text) { - case "REQ_INFO_NAME_INVALID": - shakeField(FIELD_NAME); - break; - case "REQ_INFO_PHONE_INVALID": - shakeField(FIELD_PHONE); - break; - case "REQ_INFO_EMAIL_INVALID": - shakeField(FIELD_EMAIL); - break; - case "ADDRESS_COUNTRY_INVALID": - shakeField(FIELD_COUNTRY); - break; - case "ADDRESS_CITY_INVALID": - shakeField(FIELD_CITY); - break; - case "ADDRESS_POSTCODE_INVALID": - shakeField(FIELD_POSTCODE); - break; - case "ADDRESS_STATE_INVALID": - shakeField(FIELD_STATE); - break; - case "ADDRESS_STREET_LINE1_INVALID": - shakeField(FIELD_STREET1); - break; - case "ADDRESS_STREET_LINE2_INVALID": - shakeField(FIELD_STREET2); - break; - default: - AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); - break; - } - } - } - }); - } + } + }); } }, ConnectionsManager.RequestFlagFailOnServerErrors); } @@ -2990,44 +2886,30 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen req.shipping_option_id = shippingOption.id; req.flags |= 2; } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (response != null) { - if (response instanceof TLRPC.TL_payments_paymentResult) { - MessagesController.getInstance(currentAccount).processUpdates(((TLRPC.TL_payments_paymentResult) response).updates, false); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - goToNextStep(); - } - }); - } else if (response instanceof TLRPC.TL_payments_paymentVerficationNeeded) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.paymentFinished); - setDonePressed(false); - webView.setVisibility(View.VISIBLE); - webviewLoading = true; - showEditDoneProgress(true, true); - progressView.setVisibility(View.VISIBLE); - doneItem.setEnabled(false); - doneItem.getImageView().setVisibility(View.INVISIBLE); - webView.loadUrl(((TLRPC.TL_payments_paymentVerficationNeeded) response).url); - } - }); - } - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); - setDonePressed(false); - showEditDoneProgress(false, false); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + if (response instanceof TLRPC.TL_payments_paymentResult) { + MessagesController.getInstance(currentAccount).processUpdates(((TLRPC.TL_payments_paymentResult) response).updates, false); + AndroidUtilities.runOnUIThread(this::goToNextStep); + } else if (response instanceof TLRPC.TL_payments_paymentVerficationNeeded) { + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.paymentFinished); + setDonePressed(false); + webView.setVisibility(View.VISIBLE); + webviewLoading = true; + showEditDoneProgress(true, true); + progressView.setVisibility(View.VISIBLE); + doneItem.setEnabled(false); + doneItem.getImageView().setVisibility(View.INVISIBLE); + webView.loadUrl(((TLRPC.TL_payments_paymentVerficationNeeded) response).url); }); } + } else { + AndroidUtilities.runOnUIThread(() -> { + AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); + setDonePressed(false); + showEditDoneProgress(false, false); + }); } }, ConnectionsManager.RequestFlagFailOnServerErrors); } @@ -3072,73 +2954,76 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen showEditDoneProgress(true, true); setDonePressed(true); final TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - if (response instanceof TLRPC.TL_account_noPassword) { - passwordOk = false; - goToNextStep(); - } else { - TLRPC.TL_account_password currentPassword = (TLRPC.TL_account_password) response; - byte[] passwordBytes = null; - try { - passwordBytes = password.getBytes("UTF-8"); - } catch (Exception e) { - FileLog.e(e); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_account_password currentPassword = (TLRPC.TL_account_password) response; + if (!TwoStepVerificationActivity.canHandleCurrentPassword(currentPassword, false)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + return; + } + if (!currentPassword.has_password) { + passwordOk = false; + goToNextStep(); + } else { + byte[] passwordBytes = AndroidUtilities.getStringBytes(password); - byte[] hash = new byte[currentPassword.current_salt.length * 2 + passwordBytes.length]; - System.arraycopy(currentPassword.current_salt, 0, hash, 0, currentPassword.current_salt.length); - System.arraycopy(passwordBytes, 0, hash, currentPassword.current_salt.length, passwordBytes.length); - System.arraycopy(currentPassword.current_salt, 0, hash, hash.length - currentPassword.current_salt.length, currentPassword.current_salt.length); - - final TLRPC.TL_account_getTmpPassword req = new TLRPC.TL_account_getTmpPassword(); - req.password_hash = Utilities.computeSHA256(hash, 0, hash.length); - req.period = 60 * 30; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - showEditDoneProgress(true, false); - setDonePressed(false); - if (response != null) { - passwordOk = true; - UserConfig.getInstance(currentAccount).tmpPassword = (TLRPC.TL_account_tmpPassword) response; - UserConfig.getInstance(currentAccount).saveConfig(false); - goToNextStep(); - } else { - if (error.text.equals("PASSWORD_HASH_INVALID")) { - Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); - if (v != null) { - v.vibrate(200); - } - AndroidUtilities.shakeView(inputFields[FIELD_SAVEDPASSWORD], 2, 0); - inputFields[FIELD_SAVEDPASSWORD].setText(""); - } else { - AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); - } - } - } - }); - - } - }, ConnectionsManager.RequestFlagFailOnServerErrors); - } + Utilities.globalQueue.postRunnable(() -> { + final byte x_bytes[]; + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + x_bytes = SRPHelper.getX(passwordBytes, algo); } else { - AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); + x_bytes = null; + } + + final TLRPC.TL_account_getTmpPassword req1 = new TLRPC.TL_account_getTmpPassword(); + req1.period = 60 * 30; + + RequestDelegate requestDelegate = (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { showEditDoneProgress(true, false); setDonePressed(false); + if (response1 != null) { + passwordOk = true; + UserConfig.getInstance(currentAccount).tmpPassword = (TLRPC.TL_account_tmpPassword) response1; + UserConfig.getInstance(currentAccount).saveConfig(false); + goToNextStep(); + } else { + if (error1.text.equals("PASSWORD_HASH_INVALID")) { + Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(inputFields[FIELD_SAVEDPASSWORD], 2, 0); + inputFields[FIELD_SAVEDPASSWORD].setText(""); + } else { + AlertsCreator.processError(currentAccount, error1, PaymentFormActivity.this, req1); + } + } + }); + + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + req1.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, algo); + if (req1.password == null) { + TLRPC.TL_error error2 = new TLRPC.TL_error(); + error2.text = "ALGO_INVALID"; + requestDelegate.run(null, error2); + return; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req1, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + TLRPC.TL_error error2 = new TLRPC.TL_error(); + error2.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error2); } - } - }); + }); + } + } else { + AlertsCreator.processError(currentAccount, error, PaymentFormActivity.this, req); + showEditDoneProgress(true, false); + setDonePressed(false); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } private void showEditDoneProgress(final boolean animateDoneItem, final boolean show) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 59af6cbd7..13f1c9845 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -81,6 +81,10 @@ import android.widget.Scroller; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import com.coremedia.iso.IsoFile; import com.coremedia.iso.boxes.Box; import com.coremedia.iso.boxes.MediaBox; @@ -110,9 +114,6 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.WebFile; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -7040,15 +7041,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void closePhoto(boolean animated, boolean fromEditMode) { if (!fromEditMode && currentEditMode != 0) { if (currentEditMode == 3 && photoPaintView != null) { - photoPaintView.maybeShowDismissalAlert(this, parentActivity, new Runnable() { - @Override - public void run() { - switchToEditMode(0); - } - }); + photoPaintView.maybeShowDismissalAlert(this, parentActivity, () -> switchToEditMode(0)); return; } - if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); } @@ -7082,6 +7077,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (currentEditMode == 1) { editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); + } else if (currentEditMode == 3) { + photoPaintView.shutdown(); + containerView.removeView(photoPaintView); + photoPaintView = null; } currentEditMode = 0; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index 4c328bf88..bd613c100 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Spannable; @@ -30,8 +29,6 @@ import org.telegram.messenger.R; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; @@ -140,12 +137,9 @@ public class PrivacyControlActivity extends BaseFragment implements Notification builder.setMessage(LocaleController.getString("CustomHelp", R.string.CustomHelp)); } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - applyCurrentPrivacySettings(); - preferences.edit().putBoolean("privacyAlertShowed", true).commit(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + applyCurrentPrivacySettings(); + preferences.edit().putBoolean("privacyAlertShowed", true).commit(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -173,84 +167,75 @@ public class PrivacyControlActivity extends BaseFragment implements Notification listView.setVerticalScrollBarEnabled(false); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setAdapter(listAdapter); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, final int position) { - if (position == nobodyRow || position == everybodyRow || position == myContactsRow) { - int newType = currentType; - if (position == nobodyRow) { - newType = 1; - } else if (position == everybodyRow) { - newType = 0; - } else if (position == myContactsRow) { - newType = 2; - } - if (newType == currentType) { - return; - } - enableAnimation = true; - doneButton.setVisibility(View.VISIBLE); - lastCheckedType = currentType; - currentType = newType; - updateRows(); - } else if (position == neverShareRow || position == alwaysShareRow) { - ArrayList createFromArray; - if (position == neverShareRow) { - createFromArray = currentMinus; - } else { - createFromArray = currentPlus; - } - if (createFromArray.isEmpty()) { - Bundle args = new Bundle(); - args.putBoolean(position == neverShareRow ? "isNeverShare" : "isAlwaysShare", true); - args.putBoolean("isGroup", rulesType != 0); - GroupCreateActivity fragment = new GroupCreateActivity(args); - fragment.setDelegate(new GroupCreateActivity.GroupCreateActivityDelegate() { - @Override - public void didSelectUsers(ArrayList ids) { - if (position == neverShareRow) { - currentMinus = ids; - for (int a = 0; a < currentMinus.size(); a++) { - currentPlus.remove(currentMinus.get(a)); - } - } else { - currentPlus = ids; - for (int a = 0; a < currentPlus.size(); a++) { - currentMinus.remove(currentPlus.get(a)); - } - } - doneButton.setVisibility(View.VISIBLE); - lastCheckedType = -1; - listAdapter.notifyDataSetChanged(); + listView.setOnItemClickListener((view, position) -> { + if (position == nobodyRow || position == everybodyRow || position == myContactsRow) { + int newType = currentType; + if (position == nobodyRow) { + newType = 1; + } else if (position == everybodyRow) { + newType = 0; + } else if (position == myContactsRow) { + newType = 2; + } + if (newType == currentType) { + return; + } + enableAnimation = true; + doneButton.setVisibility(View.VISIBLE); + lastCheckedType = currentType; + currentType = newType; + updateRows(); + } else if (position == neverShareRow || position == alwaysShareRow) { + ArrayList createFromArray; + if (position == neverShareRow) { + createFromArray = currentMinus; + } else { + createFromArray = currentPlus; + } + if (createFromArray.isEmpty()) { + Bundle args = new Bundle(); + args.putBoolean(position == neverShareRow ? "isNeverShare" : "isAlwaysShare", true); + args.putBoolean("isGroup", rulesType != 0); + GroupCreateActivity fragment = new GroupCreateActivity(args); + fragment.setDelegate(ids -> { + if (position == neverShareRow) { + currentMinus = ids; + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); } - }); - presentFragment(fragment); - } else { - PrivacyUsersActivity fragment = new PrivacyUsersActivity(createFromArray, rulesType != 0, position == alwaysShareRow); - fragment.setDelegate(new PrivacyUsersActivity.PrivacyActivityDelegate() { - @Override - public void didUpdatedUserList(ArrayList ids, boolean added) { - if (position == neverShareRow) { - currentMinus = ids; - if (added) { - for (int a = 0; a < currentMinus.size(); a++) { - currentPlus.remove(currentMinus.get(a)); - } - } - } else { - currentPlus = ids; - if (added) { - for (int a = 0; a < currentPlus.size(); a++) { - currentMinus.remove(currentPlus.get(a)); - } - } - } - doneButton.setVisibility(View.VISIBLE); - listAdapter.notifyDataSetChanged(); + } else { + currentPlus = ids; + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); } - }); - presentFragment(fragment); - } + } + doneButton.setVisibility(View.VISIBLE); + lastCheckedType = -1; + listAdapter.notifyDataSetChanged(); + }); + presentFragment(fragment); + } else { + PrivacyUsersActivity fragment = new PrivacyUsersActivity(createFromArray, rulesType != 0, position == alwaysShareRow); + fragment.setDelegate((ids, added) -> { + if (position == neverShareRow) { + currentMinus = ids; + if (added) { + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); + } + } + } else { + currentPlus = ids; + if (added) { + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); + } + } + } + doneButton.setVisibility(View.VISIBLE); + listAdapter.notifyDataSetChanged(); + }); + presentFragment(fragment); } } }); @@ -316,31 +301,23 @@ public class PrivacyControlActivity extends BaseFragment implements Notification progressDialog.show(); } final AlertDialog progressDialogFinal = progressDialog; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - if (progressDialogFinal != null) { - progressDialogFinal.dismiss(); - } - } catch (Exception e) { - FileLog.e(e); - } - if (error == null) { - finishFragment(); - TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; - MessagesController.getInstance(currentAccount).putUsers(rules.users, false); - ContactsController.getInstance(currentAccount).setPrivacyRules(rules.rules, rulesType); - } else { - showErrorAlert(); - } - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + if (progressDialogFinal != null) { + progressDialogFinal.dismiss(); + } + } catch (Exception e) { + FileLog.e(e); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + if (error == null) { + finishFragment(); + TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; + MessagesController.getInstance(currentAccount).putUsers(rules.users, false); + ContactsController.getInstance(currentAccount).setPrivacyRules(rules.rules, rulesType); + } else { + showErrorAlert(); + } + }), ConnectionsManager.RequestFlagFailOnServerErrors); } private void showErrorAlert() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index eae879155..6edeb9f36 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -9,7 +9,6 @@ package org.telegram.ui; import android.content.Context; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.view.View; import android.view.ViewGroup; @@ -29,8 +28,6 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.ActionBar; @@ -137,11 +134,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio UserConfig.getInstance(currentAccount).saveConfig(false); TLRPC.TL_contacts_toggleTopPeers req = new TLRPC.TL_contacts_toggleTopPeers(); req.enabled = newSuggest; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - } }); } } @@ -178,287 +172,221 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio listView.setLayoutAnimation(null); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setAdapter(listAdapter); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (!view.isEnabled()) { + listView.setOnItemClickListener((view, position) -> { + if (!view.isEnabled()) { + return; + } + if (position == blockedRow) { + presentFragment(new BlockedUsersActivity()); + } else if (position == sessionsRow) { + presentFragment(new SessionsActivity(0)); + } else if (position == webSessionsRow) { + presentFragment(new SessionsActivity(1)); + } else if (position == clearDraftsRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("AreYouSureClearDrafts", R.string.AreYouSureClearDrafts)); + builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialogInterface, i) -> { + TLRPC.TL_messages_clearAllDrafts req = new TLRPC.TL_messages_clearAllDrafts(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> DataQuery.getInstance(currentAccount).clearAllDrafts())); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (position == deleteAccountRow) { + if (getParentActivity() == null) { return; } - if (position == blockedRow) { - presentFragment(new BlockedUsersActivity()); - } else if (position == sessionsRow) { - presentFragment(new SessionsActivity(0)); - } else if (position == webSessionsRow) { - presentFragment(new SessionsActivity(1)); - } else if (position == clearDraftsRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("AreYouSureClearDrafts", R.string.AreYouSureClearDrafts)); - builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TLRPC.TL_messages_clearAllDrafts req = new TLRPC.TL_messages_clearAllDrafts(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - DataQuery.getInstance(currentAccount).clearAllDrafts(); - } - }); - } - }); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else if (position == deleteAccountRow) { - if (getParentActivity() == null) { - return; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("DeleteAccountTitle", R.string.DeleteAccountTitle)); + builder.setItems(new CharSequence[]{ + LocaleController.formatPluralString("Months", 1), + LocaleController.formatPluralString("Months", 3), + LocaleController.formatPluralString("Months", 6), + LocaleController.formatPluralString("Years", 1) + }, (dialog, which) -> { + int value = 0; + if (which == 0) { + value = 30; + } else if (which == 1) { + value = 90; + } else if (which == 2) { + value = 182; + } else if (which == 3) { + value = 365; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("DeleteAccountTitle", R.string.DeleteAccountTitle)); - builder.setItems(new CharSequence[]{ - LocaleController.formatPluralString("Months", 1), - LocaleController.formatPluralString("Months", 3), - LocaleController.formatPluralString("Months", 6), - LocaleController.formatPluralString("Years", 1) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int value = 0; - if (which == 0) { - value = 30; - } else if (which == 1) { - value = 90; - } else if (which == 2) { - value = 182; - } else if (which == 3) { - value = 365; - } - final AlertDialog progressDialog = new AlertDialog(getParentActivity(), 1); - progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(false); - progressDialog.show(); + final AlertDialog progressDialog = new AlertDialog(getParentActivity(), 1); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.show(); - final TLRPC.TL_account_setAccountTTL req = new TLRPC.TL_account_setAccountTTL(); - req.ttl = new TLRPC.TL_accountDaysTTL(); - req.ttl.days = value; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - if (response instanceof TLRPC.TL_boolTrue) { - ContactsController.getInstance(currentAccount).setDeleteAccountTTL(req.ttl.days); - listAdapter.notifyDataSetChanged(); - } - } - }); - } - }); + final TLRPC.TL_account_setAccountTTL req = new TLRPC.TL_account_setAccountTTL(); + req.ttl = new TLRPC.TL_accountDaysTTL(); + req.ttl.days = value; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else if (position == lastSeenRow) { - presentFragment(new PrivacyControlActivity(0)); - } else if (position == callsRow) { - presentFragment(new PrivacyControlActivity(2)); - } else if (position == groupsRow) { - presentFragment(new PrivacyControlActivity(1)); - } else if (position == passwordRow) { - presentFragment(new TwoStepVerificationActivity(0)); - } else if (position == passcodeRow) { - if (SharedConfig.passcodeHash.length() > 0) { - presentFragment(new PasscodeActivity(2)); - } else { - presentFragment(new PasscodeActivity(0)); - } - } else if (position == secretWebpageRow) { - if (MessagesController.getInstance(currentAccount).secretWebpagePreview == 1) { - MessagesController.getInstance(currentAccount).secretWebpagePreview = 0; - } else { - MessagesController.getInstance(currentAccount).secretWebpagePreview = 1; - } - MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", MessagesController.getInstance(currentAccount).secretWebpagePreview).commit(); - if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(MessagesController.getInstance(currentAccount).secretWebpagePreview == 1); - } - } else if (position == contactsDeleteRow) { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("Contacts", R.string.Contacts)); - builder.setMessage(LocaleController.getString("SyncContactsDeleteInfo", R.string.SyncContactsDeleteInfo)); - builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), 1); - builder.setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog = builder.show(); - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(false); - - if (currentSync != newSync) { - currentSync = UserConfig.getInstance(currentAccount).syncContacts = newSync; - UserConfig.getInstance(currentAccount).saveConfig(false); - } - ContactsController.getInstance(currentAccount).deleteAllContacts(new Runnable() { - @Override - public void run() { - progressDialog.dismiss(); - } - }); - } - }); - showDialog(builder.create()); - } else if (position == contactsSuggestRow) { - final TextCheckCell cell = (TextCheckCell) view; - if (newSuggest) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("SuggestContactsAlert", R.string.SuggestContactsAlert)); - builder.setPositiveButton(LocaleController.getString("MuteDisable", R.string.MuteDisable), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); - req.credentials = clear[1]; - req.info = clear[0]; - UserConfig.getInstance(currentAccount).tmpPassword = null; - UserConfig.getInstance(currentAccount).saveConfig(false); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newSuggest = !newSuggest; - cell.setChecked(newSuggest); - } - }); - } - }); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else { - newSuggest = !newSuggest; - cell.setChecked(newSuggest); - } - } else if (position == contactsSyncRow) { - newSync = !newSync; - if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(newSync); - } - } else if (position == callsP2PRow) { - new AlertDialog.Builder(getParentActivity()) - .setTitle(LocaleController.getString("PrivacyCallsP2PTitle", R.string.PrivacyCallsP2PTitle)) - .setItems(new String[]{ - LocaleController.getString("LastSeenEverybody", R.string.LastSeenEverybody), - LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), - LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences prefs = MessagesController.getMainSettings(currentAccount); - prefs.edit().putInt("calls_p2p_new", which).commit(); - listAdapter.notifyDataSetChanged(); - } - }) - .setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null) - .show(); - } else if (position == secretMapRow) { - AlertsCreator.showSecretLocationAlert(getParentActivity(), currentAccount, new Runnable() { - @Override - public void run() { + if (response instanceof TLRPC.TL_boolTrue) { + ContactsController.getInstance(currentAccount).setDeleteAccountTTL(req.ttl.days); listAdapter.notifyDataSetChanged(); } - }, false); - } else if (position == paymentsClearRow) { - BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); - builder.setApplyTopPadding(false); - builder.setApplyBottomPadding(false); - LinearLayout linearLayout = new LinearLayout(getParentActivity()); - linearLayout.setOrientation(LinearLayout.VERTICAL); - for (int a = 0; a < 2; a++) { - String name = null; - if (a == 0) { - name = LocaleController.getString("PrivacyClearShipping", R.string.PrivacyClearShipping); - } else if (a == 1) { - name = LocaleController.getString("PrivacyClearPayment", R.string.PrivacyClearPayment); - } - clear[a] = true; - CheckBoxCell checkBoxCell = new CheckBoxCell(getParentActivity(), 1); - checkBoxCell.setTag(a); - checkBoxCell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - linearLayout.addView(checkBoxCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - checkBoxCell.setText(name, null, true, true); - checkBoxCell.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - checkBoxCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - int num = (Integer) cell.getTag(); - clear[num] = !clear[num]; - cell.setChecked(clear[num], true); - } - }); - } - BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 1); - cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - cell.setTextAndIcon(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), 0); - cell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - } - } catch (Exception e) { - FileLog.e(e); - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("PrivacyPaymentsClearAlert", R.string.PrivacyPaymentsClearAlert)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); - req.credentials = clear[1]; - req.info = clear[0]; - UserConfig.getInstance(currentAccount).tmpPassword = null; - UserConfig.getInstance(currentAccount).saveConfig(false); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - - } - }); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } - }); - linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); - builder.setCustomView(linearLayout); - showDialog(builder.create()); - } else if (position == passportRow) { - presentFragment(new PassportActivity(PassportActivity.TYPE_PASSWORD, 0, "", "", null, null, null, null)); + })); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (position == lastSeenRow) { + presentFragment(new PrivacyControlActivity(0)); + } else if (position == callsRow) { + presentFragment(new PrivacyControlActivity(2)); + } else if (position == groupsRow) { + presentFragment(new PrivacyControlActivity(1)); + } else if (position == passwordRow) { + presentFragment(new TwoStepVerificationActivity(0)); + } else if (position == passcodeRow) { + if (SharedConfig.passcodeHash.length() > 0) { + presentFragment(new PasscodeActivity(2)); + } else { + presentFragment(new PasscodeActivity(0)); } + } else if (position == secretWebpageRow) { + if (MessagesController.getInstance(currentAccount).secretWebpagePreview == 1) { + MessagesController.getInstance(currentAccount).secretWebpagePreview = 0; + } else { + MessagesController.getInstance(currentAccount).secretWebpagePreview = 1; + } + MessagesController.getGlobalMainSettings().edit().putInt("secretWebpage2", MessagesController.getInstance(currentAccount).secretWebpagePreview).commit(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MessagesController.getInstance(currentAccount).secretWebpagePreview == 1); + } + } else if (position == contactsDeleteRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Contacts", R.string.Contacts)); + builder.setMessage(LocaleController.getString("SyncContactsDeleteInfo", R.string.SyncContactsDeleteInfo)); + builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + AlertDialog.Builder builder12 = new AlertDialog.Builder(getParentActivity(), 1); + builder12.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog = builder12.show(); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + if (currentSync != newSync) { + currentSync = UserConfig.getInstance(currentAccount).syncContacts = newSync; + UserConfig.getInstance(currentAccount).saveConfig(false); + } + ContactsController.getInstance(currentAccount).deleteAllContacts(() -> progressDialog.dismiss()); + }); + showDialog(builder.create()); + } else if (position == contactsSuggestRow) { + final TextCheckCell cell = (TextCheckCell) view; + if (newSuggest) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("SuggestContactsAlert", R.string.SuggestContactsAlert)); + builder.setPositiveButton(LocaleController.getString("MuteDisable", R.string.MuteDisable), (dialogInterface, i) -> { + TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); + req.credentials = clear[1]; + req.info = clear[0]; + UserConfig.getInstance(currentAccount).tmpPassword = null; + UserConfig.getInstance(currentAccount).saveConfig(false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + newSuggest = !newSuggest; + cell.setChecked(newSuggest); + })); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else { + newSuggest = !newSuggest; + cell.setChecked(newSuggest); + } + } else if (position == contactsSyncRow) { + newSync = !newSync; + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(newSync); + } + } else if (position == callsP2PRow) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("PrivacyCallsP2PTitle", R.string.PrivacyCallsP2PTitle)) + .setItems(new String[]{ + LocaleController.getString("LastSeenEverybody", R.string.LastSeenEverybody), + LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), + LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody) + }, (dialog, which) -> { + SharedPreferences prefs = MessagesController.getMainSettings(currentAccount); + prefs.edit().putInt("calls_p2p_new", which).commit(); + listAdapter.notifyDataSetChanged(); + }) + .setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null) + .show(); + } else if (position == secretMapRow) { + AlertsCreator.showSecretLocationAlert(getParentActivity(), currentAccount, () -> listAdapter.notifyDataSetChanged(), false); + } else if (position == paymentsClearRow) { + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setApplyTopPadding(false); + builder.setApplyBottomPadding(false); + LinearLayout linearLayout = new LinearLayout(getParentActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + for (int a = 0; a < 2; a++) { + String name = null; + if (a == 0) { + name = LocaleController.getString("PrivacyClearShipping", R.string.PrivacyClearShipping); + } else if (a == 1) { + name = LocaleController.getString("PrivacyClearPayment", R.string.PrivacyClearPayment); + } + clear[a] = true; + CheckBoxCell checkBoxCell = new CheckBoxCell(getParentActivity(), 1); + checkBoxCell.setTag(a); + checkBoxCell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + linearLayout.addView(checkBoxCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + checkBoxCell.setText(name, null, true, true); + checkBoxCell.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + checkBoxCell.setOnClickListener(v -> { + CheckBoxCell cell = (CheckBoxCell) v; + int num = (Integer) cell.getTag(); + clear[num] = !clear[num]; + cell.setChecked(clear[num], true); + }); + } + BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 1); + cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + cell.setTextAndIcon(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), 0); + cell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText)); + cell.setOnClickListener(v -> { + try { + if (visibleDialog != null) { + visibleDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e(e); + } + AlertDialog.Builder builder1 = new AlertDialog.Builder(getParentActivity()); + builder1.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder1.setMessage(LocaleController.getString("PrivacyPaymentsClearAlert", R.string.PrivacyPaymentsClearAlert)); + builder1.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + TLRPC.TL_payments_clearSavedInfo req = new TLRPC.TL_payments_clearSavedInfo(); + req.credentials = clear[1]; + req.info = clear[0]; + UserConfig.getInstance(currentAccount).tmpPassword = null; + UserConfig.getInstance(currentAccount).saveConfig(false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }); + }); + builder1.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder1.create()); + }); + linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + builder.setCustomView(linearLayout); + showDialog(builder.create()); + } else if (position == passportRow) { + presentFragment(new PassportActivity(PassportActivity.TYPE_PASSWORD, 0, "", "", null, null, null, null)); } }); @@ -522,21 +450,15 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio return; } TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - if (response != null) { - TLRPC.account_Password password = (TLRPC.account_Password) response; - if (password.has_secure_values) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - UserConfig.getInstance(currentAccount).hasSecureData = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - updateRows(); - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.TL_account_password password = (TLRPC.TL_account_password) response; + if (password.has_secure_values) { + AndroidUtilities.runOnUIThread(() -> { + UserConfig.getInstance(currentAccount).hasSecureData = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + updateRows(); + }); } } }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 9eb4acdea..b870e7860 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -16,7 +16,6 @@ import android.animation.StateListAnimator; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -46,7 +45,6 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -56,7 +54,6 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.DataQuery; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesStorage; -import org.telegram.messenger.NotificationsController; import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserObject; @@ -64,8 +61,6 @@ import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; @@ -105,7 +100,6 @@ import org.telegram.ui.Components.voip.VoIPHelper; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.concurrent.CountDownLatch; public class ProfileActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate { @@ -314,7 +308,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentEncryptedChat != null) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didReceivedNewMessages); } - userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.contains(user_id); + userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.indexOfKey(user_id) >= 0; if (user.bot) { isBot = true; DataQuery.getInstance(currentAccount).loadBotInfo(user.id, true, classGuid); @@ -325,12 +319,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. currentChat = MessagesController.getInstance(currentAccount).getChat(chat_id); if (currentChat == null) { final CountDownLatch countDownLatch = new CountDownLatch(1); - MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - currentChat = MessagesStorage.getInstance(currentAccount).getChat(chat_id); - countDownLatch.countDown(); - } + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + currentChat = MessagesStorage.getInstance(currentAccount).getChat(chat_id); + countDownLatch.countDown(); }); try { countDownLatch.await(); @@ -355,12 +346,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. updateOnlineCount(); imageUpdater = new ImageUpdater(); - imageUpdater.delegate = new ImageUpdater.ImageUpdaterDelegate() { - @Override - public void didUploadedPhoto(TLRPC.InputFile file, TLRPC.PhotoSize small, TLRPC.PhotoSize big, TLRPC.TL_secureFile secureFile) { - if (chat_id != 0) { - MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, file); - } + imageUpdater.delegate = (file, small, big, secureFile) -> { + if (chat_id != 0) { + MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, file); } }; imageUpdater.parentFragment = this; @@ -464,14 +452,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. builder.setMessage(LocaleController.getString("AreYouSureUnblockContact", R.string.AreYouSureUnblockContact)); } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (!userBlocked) { - MessagesController.getInstance(currentAccount).blockUser(user_id); - } else { - MessagesController.getInstance(currentAccount).unblockUser(user_id); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (!userBlocked) { + MessagesController.getInstance(currentAccount).blockUser(user_id); + } else { + MessagesController.getInstance(currentAccount).unblockUser(user_id); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -511,13 +496,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("AreYouSureDeleteContact", R.string.AreYouSureDeleteContact)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ArrayList arrayList = new ArrayList<>(); - arrayList.add(user); - ContactsController.getInstance(currentAccount).deleteContact(arrayList); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(user); + ContactsController.getInstance(currentAccount).deleteContact(arrayList); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -543,23 +525,20 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. args.putInt("dialogsType", 2); args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupTitle", R.string.AddToTheGroupTitle, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { - long did = dids.get(0); - Bundle args = new Bundle(); - args.putBoolean("scrollToTopOnResume", true); - args.putInt("chat_id", -(int) did); - if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, fragment)) { - return; - } - - NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance(currentAccount).addUserToChat(-(int) did, user, null, 0, null, ProfileActivity.this); - presentFragment(new ChatActivity(args), true); - removeSelfFromStack(); + fragment.setDelegate((fragment1, dids, message, param) -> { + long did = dids.get(0); + Bundle args1 = new Bundle(); + args1.putBoolean("scrollToTopOnResume", true); + args1.putInt("chat_id", -(int) did); + if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { + return; } + + NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance(currentAccount).addUserToChat(-(int) did, user, null, 0, null, ProfileActivity.this); + presentFragment(new ChatActivity(args1), true); + removeSelfFromStack(); }); presentFragment(fragment); } else if (id == share) { @@ -671,359 +650,231 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); listView.setAdapter(listAdapter); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, final int position) { - if (getParentActivity() == null) { + listView.setOnItemClickListener((view, position) -> { + if (getParentActivity() == null) { + return; + } + if (position == sharedMediaRow) { + Bundle args = new Bundle(); + if (user_id != 0) { + args.putLong("dialog_id", dialog_id != 0 ? dialog_id : user_id); + } else { + args.putLong("dialog_id", -chat_id); + } + int[] media = new int[DataQuery.MEDIA_TYPES_COUNT]; + for (int a = 0; a < media.length; a++) { + media[a] = mediaCount[a]; + if (mediaCount[a] >= 0 && mediaMergeCount[a] >= 0) { + media[a] = mediaCount[a] + mediaMergeCount[a]; + } else if (mediaCount[a] >= 0) { + media[a] = mediaCount[a]; + } else if (mediaMergeCount[a] >= 0) { + media[a] = mediaMergeCount[a]; + } else { + media[a] = -1; + } + } + MediaActivity fragment = new MediaActivity(args, media); + fragment.setChatInfo(info); + presentFragment(fragment); + } else if (position == groupsInCommonRow) { + presentFragment(new CommonGroupsActivity(user_id)); + } else if (position == settingsKeyRow) { + Bundle args = new Bundle(); + args.putInt("chat_id", (int) (dialog_id >> 32)); + presentFragment(new IdenticonActivity(args)); + } else if (position == settingsTimerRow) { + showDialog(AlertsCreator.createTTLAlert(getParentActivity(), currentEncryptedChat).create()); + } else if (position == settingsNotificationsRow) { + final long did; + if (dialog_id != 0) { + did = dialog_id; + } else if (user_id != 0) { + did = user_id; + } else { + did = -chat_id; + } + AlertsCreator.showCustomNotificationsDialog(ProfileActivity.this, did, currentAccount, param -> listAdapter.notifyItemChanged(settingsNotificationsRow)); + } else if (position == startSecretChatRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("AreYouSureSecretChat", R.string.AreYouSureSecretChat)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + creatingChat = true; + SecretChatHelper.getInstance(currentAccount).startSecretChat(getParentActivity(), MessagesController.getInstance(currentAccount).getUser(user_id)); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (position > emptyRowChat2 && position < membersEndRow) { + int user_id; + if (!sortedUsers.isEmpty()) { + user_id = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)).user_id; + } else { + user_id = info.participants.participants.get(position - emptyRowChat2 - 1).user_id; + } + if (user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { return; } - if (position == sharedMediaRow) { - Bundle args = new Bundle(); - if (user_id != 0) { - args.putLong("dialog_id", dialog_id != 0 ? dialog_id : user_id); + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ProfileActivity(args)); + } else if (position == addMemberRow) { + openAddMember(); + } else if (position == channelNameRow) { + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + if (info.about != null && info.about.length() > 0) { + intent.putExtra(Intent.EXTRA_TEXT, currentChat.title + "\n" + info.about + "\nhttps://" + MessagesController.getInstance(currentAccount).linkPrefix + "/" + currentChat.username); } else { - args.putLong("dialog_id", -chat_id); + intent.putExtra(Intent.EXTRA_TEXT, currentChat.title + "\nhttps://" + MessagesController.getInstance(currentAccount).linkPrefix + "/" + currentChat.username); } - int[] media = new int[DataQuery.MEDIA_TYPES_COUNT]; - for (int a = 0; a < media.length; a++) { - media[a] = mediaCount[a]; - if (mediaCount[a] >= 0 && mediaMergeCount[a] >= 0) { - media[a] = mediaCount[a] + mediaMergeCount[a]; - } else if (mediaCount[a] >= 0) { - media[a] = mediaCount[a]; - } else if (mediaMergeCount[a] >= 0) { - media[a] = mediaMergeCount[a]; - } else { - media[a] = -1; - } - } - MediaActivity fragment = new MediaActivity(args, media); - fragment.setChatInfo(info); - presentFragment(fragment); - } else if (position == groupsInCommonRow) { - presentFragment(new CommonGroupsActivity(user_id)); - } else if (position == settingsKeyRow) { - Bundle args = new Bundle(); - args.putInt("chat_id", (int) (dialog_id >> 32)); - presentFragment(new IdenticonActivity(args)); - } else if (position == settingsTimerRow) { - showDialog(AlertsCreator.createTTLAlert(getParentActivity(), currentEncryptedChat).create()); - } else if (position == settingsNotificationsRow) { - final long did; - boolean enabled; - if (dialog_id != 0) { - did = dialog_id; - } else if (user_id != 0) { - did = user_id; - } else { - did = -chat_id; - } - - boolean defaultEnabled; - if ((int) did < 0) { - defaultEnabled = MessagesController.getNotificationsSettings(currentAccount).getBoolean("EnableGroup", true); - } else { - defaultEnabled = MessagesController.getNotificationsSettings(currentAccount).getBoolean("EnableAll", true); - } - - String[] descriptions = new String[]{ - defaultEnabled ? LocaleController.getString("NotificationsDefaultOn", R.string.NotificationsDefaultOn) : LocaleController.getString("NotificationsDefaultOff", R.string.NotificationsDefaultOff), - LocaleController.getString("NotificationsTurnOn", R.string.NotificationsTurnOn), - LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Hours", 1)), - LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Days", 2)), - LocaleController.getString("NotificationsCustomize", R.string.NotificationsCustomize), - LocaleController.getString("NotificationsTurnOff", R.string.NotificationsTurnOff) - }; - - int[] icons = new int[]{ - defaultEnabled ? R.drawable.notifications_s_on : R.drawable.notifications_s_off, - R.drawable.notifications_s_on, - R.drawable.notifications_s_1h, - R.drawable.notifications_s_2d, - R.drawable.notifications_s_custom, - R.drawable.notifications_s_off - }; - - final LinearLayout linearLayout = new LinearLayout(getParentActivity()); - linearLayout.setOrientation(LinearLayout.VERTICAL); - - for (int a = 0; a < descriptions.length; a++) { - TextView textView = new TextView(getParentActivity()); - textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setLines(1); - textView.setMaxLines(1); - Drawable drawable = getParentActivity().getResources().getDrawable(icons[a]); - drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogIcon), PorterDuff.Mode.MULTIPLY)); - textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); - textView.setTag(a); - textView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - textView.setPadding(AndroidUtilities.dp(24), 0, AndroidUtilities.dp(24), 0); - textView.setSingleLine(true); - textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); - textView.setCompoundDrawablePadding(AndroidUtilities.dp(26)); - textView.setText(descriptions[a]); - linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP)); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int i = (Integer) v.getTag(); - if (i == 0 || i == 1) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - if (i == 0) { - editor.remove("notify2_" + did); - } else { - editor.putInt("notify2_" + did, 0); - } - MessagesStorage.getInstance(currentAccount).setDialogFlags(did, 0); - editor.commit(); - TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - } - NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); - } else if (i == 4) { - Bundle args = new Bundle(); - args.putLong("dialog_id", did); - presentFragment(new ProfileNotificationsActivity(args)); - } else { - int untilTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - if (i == 2) { - untilTime += 60 * 60; - } else if (i == 3) { - untilTime += 60 * 60 * 48; - } else if (i == 5) { - untilTime = Integer.MAX_VALUE; - } - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - SharedPreferences.Editor editor = preferences.edit(); - long flags; - if (i == 5) { - editor.putInt("notify2_" + did, 2); - flags = 1; - } else { - editor.putInt("notify2_" + did, 3); - editor.putInt("notifyuntil_" + did, untilTime); - flags = ((long) untilTime << 32) | 1; - } - NotificationsController.getInstance(currentAccount).removeNotificationsForDialog(did); - MessagesStorage.getInstance(currentAccount).setDialogFlags(did, flags); - editor.commit(); - TLRPC.TL_dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(did); - if (dialog != null) { - dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); - dialog.notify_settings.mute_until = untilTime; - } - NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(did); - } - listAdapter.notifyItemChanged(settingsNotificationsRow); - dismissCurrentDialig(); - } - }); - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("Notifications", R.string.Notifications)); - builder.setView(linearLayout); - showDialog(builder.create()); - } else if (position == startSecretChatRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("AreYouSureSecretChat", R.string.AreYouSureSecretChat)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - creatingChat = true; - SecretChatHelper.getInstance(currentAccount).startSecretChat(getParentActivity(), MessagesController.getInstance(currentAccount).getUser(user_id)); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else if (position > emptyRowChat2 && position < membersEndRow) { - int user_id; - if (!sortedUsers.isEmpty()) { - user_id = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)).user_id; - } else { - user_id = info.participants.participants.get(position - emptyRowChat2 - 1).user_id; - } - if (user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - return; - } - Bundle args = new Bundle(); - args.putInt("user_id", user_id); - presentFragment(new ProfileActivity(args)); - } else if (position == addMemberRow) { - openAddMember(); - } else if (position == channelNameRow) { - try { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - if (info.about != null && info.about.length() > 0) { - intent.putExtra(Intent.EXTRA_TEXT, currentChat.title + "\n" + info.about + "\nhttps://" + MessagesController.getInstance(currentAccount).linkPrefix + "/" + currentChat.username); - } else { - intent.putExtra(Intent.EXTRA_TEXT, currentChat.title + "\nhttps://" + MessagesController.getInstance(currentAccount).linkPrefix + "/" + currentChat.username); - } - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("BotShare", R.string.BotShare)), 500); - } catch (Exception e) { - FileLog.e(e); - } - } else if (position == leaveChannelRow) { - leaveChatPressed(); - } else if (position == membersRow) { - Bundle args = new Bundle(); - args.putInt("chat_id", chat_id); - args.putInt("type", 2); - presentFragment(new ChannelUsersActivity(args)); - } else if (position == convertRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("ConvertGroupAlert", R.string.ConvertGroupAlert)); - builder.setTitle(LocaleController.getString("ConvertGroupAlertWarning", R.string.ConvertGroupAlertWarning)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chat_id); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else { - processOnClickOrPress(position); + getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("BotShare", R.string.BotShare)), 500); + } catch (Exception e) { + FileLog.e(e); } + } else if (position == leaveChannelRow) { + leaveChatPressed(); + } else if (position == membersRow) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat_id); + args.putInt("type", 2); + presentFragment(new ChannelUsersActivity(args)); + } else if (position == convertRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("ConvertGroupAlert", R.string.ConvertGroupAlert)); + builder.setTitle(LocaleController.getString("ConvertGroupAlertWarning", R.string.ConvertGroupAlertWarning)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).convertToMegaGroup(getParentActivity(), chat_id)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else { + processOnClickOrPress(position); } }); - listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { - @Override - public boolean onItemClick(View view, int position) { - if (position > emptyRowChat2 && position < membersEndRow) { - if (getParentActivity() == null) { + listView.setOnItemLongClickListener((view, position) -> { + if (position > emptyRowChat2 && position < membersEndRow) { + if (getParentActivity() == null) { + return false; + } + boolean allowKick = false; + boolean allowSetAdmin = false; + boolean canEditAdmin = false; + final TLRPC.ChannelParticipant channelParticipant; + + final TLRPC.ChatParticipant user; + if (!sortedUsers.isEmpty()) { + user = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)); + } else { + user = info.participants.participants.get(position - emptyRowChat2 - 1); + } + selectedUser = user.user_id; + + if (ChatObject.isChannel(currentChat)) { + channelParticipant = ((TLRPC.TL_chatChannelParticipant) user).channelParticipant; + if (user.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { return false; } - boolean allowKick = false; - boolean allowSetAdmin = false; - boolean canEditAdmin = false; - final TLRPC.ChannelParticipant channelParticipant; - - final TLRPC.ChatParticipant user; - if (!sortedUsers.isEmpty()) { - user = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)); - } else { - user = info.participants.participants.get(position - emptyRowChat2 - 1); - } - selectedUser = user.user_id; - - if (ChatObject.isChannel(currentChat)) { - channelParticipant = ((TLRPC.TL_chatChannelParticipant) user).channelParticipant; - if (user.user_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - return false; - } - TLRPC.User u = MessagesController.getInstance(currentAccount).getUser(user.user_id); - allowSetAdmin = channelParticipant instanceof TLRPC.TL_channelParticipant || channelParticipant instanceof TLRPC.TL_channelParticipantBanned; - canEditAdmin = !(channelParticipant instanceof TLRPC.TL_channelParticipantAdmin || channelParticipant instanceof TLRPC.TL_channelParticipantCreator) || channelParticipant.can_edit; - } else { - channelParticipant = null; - if (user.user_id != UserConfig.getInstance(currentAccount).getClientUserId()) { - if (currentChat.creator) { + TLRPC.User u = MessagesController.getInstance(currentAccount).getUser(user.user_id); + allowSetAdmin = channelParticipant instanceof TLRPC.TL_channelParticipant || channelParticipant instanceof TLRPC.TL_channelParticipantBanned; + canEditAdmin = !(channelParticipant instanceof TLRPC.TL_channelParticipantAdmin || channelParticipant instanceof TLRPC.TL_channelParticipantCreator) || channelParticipant.can_edit; + } else { + channelParticipant = null; + if (user.user_id != UserConfig.getInstance(currentAccount).getClientUserId()) { + if (currentChat.creator) { + allowKick = true; + } else if (user instanceof TLRPC.TL_chatParticipant) { + if (currentChat.admin && currentChat.admins_enabled || user.inviter_id == UserConfig.getInstance(currentAccount).getClientUserId()) { allowKick = true; - } else if (user instanceof TLRPC.TL_chatParticipant) { - if (currentChat.admin && currentChat.admins_enabled || user.inviter_id == UserConfig.getInstance(currentAccount).getClientUserId()) { - allowKick = true; - } } } - if (!allowKick) { - return false; - } } - - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - - ArrayList items = new ArrayList<>(); - final ArrayList actions = new ArrayList<>(); - if (currentChat.megagroup) { - if (allowSetAdmin && ChatObject.canAddAdmins(currentChat)) { - items.add(LocaleController.getString("SetAsAdmin", R.string.SetAsAdmin)); - actions.add(0); - } - if (ChatObject.canBlockUsers(currentChat) && canEditAdmin) { - items.add(LocaleController.getString("KickFromSupergroup", R.string.KickFromSupergroup)); - actions.add(1); - items.add(LocaleController.getString("KickFromGroup", R.string.KickFromGroup)); - actions.add(2); - } - } else { - items.add(chat_id > 0 ? LocaleController.getString("KickFromGroup", R.string.KickFromGroup) : LocaleController.getString("KickFromBroadcast", R.string.KickFromBroadcast)); - actions.add(2); - } - if (items.isEmpty()) { + if (!allowKick) { return false; } - builder.setItems(items.toArray(new CharSequence[items.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, final int i) { - if (actions.get(i) == 2) { - kickUser(selectedUser); - } else { - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user.user_id, chat_id, channelParticipant.admin_rights, channelParticipant.banned_rights, actions.get(i), true); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - if (actions.get(i) == 0) { - TLRPC.TL_chatChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) user); - if (rights == 1) { - channelParticipant.channelParticipant = new TLRPC.TL_channelParticipantAdmin(); - } else { - channelParticipant.channelParticipant = new TLRPC.TL_channelParticipant(); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + + ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + if (currentChat.megagroup) { + if (allowSetAdmin && ChatObject.canAddAdmins(currentChat)) { + items.add(LocaleController.getString("SetAsAdmin", R.string.SetAsAdmin)); + actions.add(0); + } + if (ChatObject.canBlockUsers(currentChat) && canEditAdmin) { + items.add(LocaleController.getString("KickFromSupergroup", R.string.KickFromSupergroup)); + actions.add(1); + items.add(LocaleController.getString("KickFromGroup", R.string.KickFromGroup)); + actions.add(2); + } + } else { + items.add(chat_id > 0 ? LocaleController.getString("KickFromGroup", R.string.KickFromGroup) : LocaleController.getString("KickFromBroadcast", R.string.KickFromBroadcast)); + actions.add(2); + } + if (items.isEmpty()) { + return false; + } + builder.setItems(items.toArray(new CharSequence[items.size()]), (dialogInterface, i) -> { + if (actions.get(i) == 2) { + kickUser(selectedUser); + } else { + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user.user_id, chat_id, channelParticipant.admin_rights, channelParticipant.banned_rights, actions.get(i), true); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> { + if (actions.get(i) == 0) { + TLRPC.TL_chatChannelParticipant channelParticipant1 = ((TLRPC.TL_chatChannelParticipant) user); + if (rights == 1) { + channelParticipant1.channelParticipant = new TLRPC.TL_channelParticipantAdmin(); + } else { + channelParticipant1.channelParticipant = new TLRPC.TL_channelParticipant(); + } + channelParticipant1.channelParticipant.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); + channelParticipant1.channelParticipant.user_id = user.user_id; + channelParticipant1.channelParticipant.date = user.date; + channelParticipant1.channelParticipant.banned_rights = rightsBanned; + channelParticipant1.channelParticipant.admin_rights = rightsAdmin; + } else if (actions.get(i) == 1) { + if (rights == 0) { + if (currentChat.megagroup && info != null && info.participants != null) { + boolean changed = false; + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) info.participants.participants.get(a)).channelParticipant; + if (p.user_id == user.user_id) { + if (info != null) { + info.participants_count--; + } + info.participants.participants.remove(a); + changed = true; + break; } - channelParticipant.channelParticipant.inviter_id = UserConfig.getInstance(currentAccount).getClientUserId(); - channelParticipant.channelParticipant.user_id = user.user_id; - channelParticipant.channelParticipant.date = user.date; - channelParticipant.channelParticipant.banned_rights = rightsBanned; - channelParticipant.channelParticipant.admin_rights = rightsAdmin; - } else if (actions.get(i) == 1) { - if (rights == 0) { - if (currentChat.megagroup && info != null && info.participants != null) { - boolean changed = false; - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) info.participants.participants.get(a)).channelParticipant; - if (p.user_id == user.user_id) { - if (info != null) { - info.participants_count--; - } - info.participants.participants.remove(a); - changed = true; - break; - } - } - if (info != null && info.participants != null) { - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant p = info.participants.participants.get(a); - if (p.user_id == user.user_id) { - info.participants.participants.remove(a); - changed = true; - break; - } - } - } - if (changed) { - updateOnlineCount(); - updateRowsIds(); - listAdapter.notifyDataSetChanged(); - } + } + if (info != null && info.participants != null) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant p = info.participants.participants.get(a); + if (p.user_id == user.user_id) { + info.participants.participants.remove(a); + changed = true; + break; } } } + if (changed) { + updateOnlineCount(); + updateRowsIds(); + listAdapter.notifyDataSetChanged(); + } } - }); - presentFragment(fragment); + } } - } - }); - showDialog(builder.create()); - return true; - } else { - return processOnClickOrPress(position); - } + }); + presentFragment(fragment); + } + }); + showDialog(builder.create()); + return true; + } else { + return processOnClickOrPress(position); } }); @@ -1032,17 +883,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); req.channel = MessagesController.getInstance(currentAccount).getInputChannel(banFromGroup); req.user_id = MessagesController.getInstance(currentAccount).getInputUser(user_id); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, TLRPC.TL_error error) { - if (response != null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - currentChannelParticipant = ((TLRPC.TL_channels_channelParticipant) response).participant; - } - }); - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> currentChannelParticipant = ((TLRPC.TL_channels_channelParticipant) response).participant); } }); } @@ -1058,18 +901,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. frameLayout1.setWillNotDraw(false); frameLayout.addView(frameLayout1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.LEFT | Gravity.BOTTOM)); - frameLayout1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, banFromGroup, null, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, 1, true); - fragment.setDelegate(new ChannelRightsEditActivity.ChannelRightsEditActivityDelegate() { - @Override - public void didSetRights(int rights, TLRPC.TL_channelAdminRights rightsAdmin, TLRPC.TL_channelBannedRights rightsBanned) { - removeSelfFromStack(); - } - }); - presentFragment(fragment); - } + frameLayout1.setOnClickListener(v -> { + ChannelRightsEditActivity fragment = new ChannelRightsEditActivity(user_id, banFromGroup, null, currentChannelParticipant != null ? currentChannelParticipant.banned_rights : null, 1, true); + fragment.setDelegate((rights, rightsAdmin, rightsBanned) -> removeSelfFromStack()); + presentFragment(fragment); }); TextView textView = new TextView(context); @@ -1097,21 +932,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. avatarImage.setPivotX(0); avatarImage.setPivotY(0); frameLayout.addView(avatarImage, LayoutHelper.createFrame(42, 42, Gravity.TOP | Gravity.LEFT, 64, 0, 0, 0)); - avatarImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (user_id != 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); - if (user.photo != null && user.photo.photo_big != null) { - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(user.photo.photo_big, provider); - } - } else if (chat_id != 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chat_id); - if (chat.photo != null && chat.photo.photo_big != null) { - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(chat.photo.photo_big, provider); - } + avatarImage.setOnClickListener(v -> { + if (user_id != 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); + if (user.photo != null && user.photo.photo_big != null) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(user.photo.photo_big, provider); + } + } else if (chat_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chat_id); + if (chat.photo != null && chat.photo.photo_big != null) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(chat.photo.photo_big, provider); } } }); @@ -1182,22 +1014,35 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); } - writeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getParentActivity() == null) { - return; + writeButton.setOnClickListener(v -> { + if (getParentActivity() == null) { + return; + } + if (user_id != 0) { + if (playProfileAnimation && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) instanceof ChatActivity) { + finishFragment(); + } else { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); + if (user == null || user instanceof TLRPC.TL_userEmpty) { + return; + } + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, ProfileActivity.this)) { + return; + } + NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + presentFragment(new ChatActivity(args), true); } - if (user_id != 0) { + } else if (chat_id != 0) { + boolean isChannel = ChatObject.isChannel(currentChat); + if (isChannel && !ChatObject.canEditInfo(currentChat) || !isChannel && !currentChat.admin && !currentChat.creator && currentChat.admins_enabled) { if (playProfileAnimation && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) instanceof ChatActivity) { finishFragment(); } else { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); - if (user == null || user instanceof TLRPC.TL_userEmpty) { - return; - } Bundle args = new Bundle(); - args.putInt("user_id", user_id); + args.putInt("chat_id", currentChat.id); if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, ProfileActivity.this)) { return; } @@ -1205,45 +1050,26 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); presentFragment(new ChatActivity(args), true); } - } else if (chat_id != 0) { - boolean isChannel = ChatObject.isChannel(currentChat); - if (isChannel && !ChatObject.canEditInfo(currentChat) || !isChannel && !currentChat.admin && !currentChat.creator && currentChat.admins_enabled) { - if (playProfileAnimation && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) instanceof ChatActivity) { - finishFragment(); - } else { - Bundle args = new Bundle(); - args.putInt("chat_id", currentChat.id); - if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args, ProfileActivity.this)) { - return; - } - NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - presentFragment(new ChatActivity(args), true); - } + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + CharSequence[] items; + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chat_id); + if (chat.photo == null || chat.photo.photo_big == null || chat.photo instanceof TLRPC.TL_chatPhotoEmpty) { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - CharSequence[] items; - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chat_id); - if (chat.photo == null || chat.photo.photo_big == null || chat.photo instanceof TLRPC.TL_chatPhotoEmpty) { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; - } else { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; - } - - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - imageUpdater.openCamera(); - } else if (i == 1) { - imageUpdater.openGallery(); - } else if (i == 2) { - MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null); - } - } - }); - showDialog(builder.create()); + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; } + + builder.setItems(items, (dialogInterface, i) -> { + if (i == 0) { + imageUpdater.openCamera(); + } else if (i == 1) { + imageUpdater.openGallery(); + } else if (i == 2) { + MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null); + } + }); + showDialog(builder.create()); } } }); @@ -1280,18 +1106,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. username = chat.username; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - try { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", "@" + username); - clipboard.setPrimaryClip(clip); - Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, (dialogInterface, i) -> { + if (i == 0) { + try { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", "@" + username); + clipboard.setPrimaryClip(clip); + Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); } } }); @@ -1315,55 +1138,49 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. actions.add(0); items.add(LocaleController.getString("Copy", R.string.Copy)); actions.add(1); - builder.setItems(items.toArray(new CharSequence[items.size()]), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - i = actions.get(i); - if (i == 0) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+" + user.phone)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getParentActivity().startActivityForResult(intent, 500); - } catch (Exception e) { - FileLog.e(e); - } - } else if (i == 1) { - try { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", "+" + user.phone); - clipboard.setPrimaryClip(clip); - Toast.makeText(getParentActivity(), LocaleController.getString("PhoneCopied", R.string.PhoneCopied), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); - } - } else if (i == 2) { - VoIPHelper.startCall(user, getParentActivity(), MessagesController.getInstance(currentAccount).getUserFull(user.id)); + builder.setItems(items.toArray(new CharSequence[items.size()]), (dialogInterface, i) -> { + i = actions.get(i); + if (i == 0) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+" + user.phone)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e(e); } + } else if (i == 1) { + try { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", "+" + user.phone); + clipboard.setPrimaryClip(clip); + Toast.makeText(getParentActivity(), LocaleController.getString("PhoneCopied", R.string.PhoneCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); + } + } else if (i == 2) { + VoIPHelper.startCall(user, getParentActivity(), MessagesController.getInstance(currentAccount).getUserFull(user.id)); } }); showDialog(builder.create()); return true; } else if (position == channelInfoRow || position == userInfoRow || position == userInfoDetailedRow) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - String about; - if (position == channelInfoRow) { - about = info.about; - } else { - TLRPC.TL_userFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user_id); - about = userFull != null ? userFull.about : null; - } - if (TextUtils.isEmpty(about)) { - return; - } - AndroidUtilities.addToClipboard(about); - Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - FileLog.e(e); + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, (dialogInterface, i) -> { + try { + String about; + if (position == channelInfoRow) { + about = info.about; + } else { + TLRPC.TL_userFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user_id); + about = userFull != null ? userFull.about : null; } + if (TextUtils.isEmpty(about)) { + return; + } + AndroidUtilities.addToClipboard(about); + Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e(e); } }); showDialog(builder.create()); @@ -1380,12 +1197,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. builder.setMessage(LocaleController.getString("AreYouSureDeleteAndExit", R.string.AreYouSureDeleteAndExit)); } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - kickUser(0); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> kickUser(0)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } @@ -1428,46 +1240,38 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. req.filter = new TLRPC.TL_channelParticipantsRecent(); req.offset = reload ? 0 : participantsMap.size(); req.limit = 200; - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - if (res.users.size() < 200) { - usersEndReached = true; - } - if (req.offset == 0) { - participantsMap.clear(); - info.participants = new TLRPC.TL_chatParticipants(); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); - MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); - } - for (int a = 0; a < res.participants.size(); a++) { - TLRPC.TL_chatChannelParticipant participant = new TLRPC.TL_chatChannelParticipant(); - participant.channelParticipant = res.participants.get(a); - participant.inviter_id = participant.channelParticipant.inviter_id; - participant.user_id = participant.channelParticipant.user_id; - participant.date = participant.channelParticipant.date; - if (participantsMap.indexOfKey(participant.user_id) < 0) { - info.participants.participants.add(participant); - participantsMap.put(participant.user_id, participant); - } - } - } - updateOnlineCount(); - loadingUsers = false; - updateRowsIds(); - if (listAdapter != null) { - listAdapter.notifyDataSetChanged(); - } + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + if (res.users.size() < 200) { + usersEndReached = true; + } + if (req.offset == 0) { + participantsMap.clear(); + info.participants = new TLRPC.TL_chatParticipants(); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance(currentAccount).updateChannelUsers(chat_id, res.participants); + } + for (int a = 0; a < res.participants.size(); a++) { + TLRPC.TL_chatChannelParticipant participant = new TLRPC.TL_chatChannelParticipant(); + participant.channelParticipant = res.participants.get(a); + participant.inviter_id = participant.channelParticipant.inviter_id; + participant.user_id = participant.channelParticipant.user_id; + participant.date = participant.channelParticipant.date; + if (participantsMap.indexOfKey(participant.user_id) < 0) { + info.participants.participants.add(participant); + participantsMap.put(participant.user_id, participant); } - }, delay); + } } - }); + updateOnlineCount(); + loadingUsers = false; + updateRowsIds(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + }, delay)); ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); } @@ -1485,12 +1289,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. args.putString("selectAlertString", LocaleController.getString("AddToTheGroup", R.string.AddToTheGroup)); } ContactsActivity fragment = new ContactsActivity(args); - fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() { - @Override - public void didSelectContact(TLRPC.User user, String param, ContactsActivity activity) { - MessagesController.getInstance(currentAccount).addUserToChat(chat_id, user, info, param != null ? Utilities.parseInt(param) : 0, null, ProfileActivity.this); - } - }); + fragment.setDelegate((user, param, activity) -> MessagesController.getInstance(currentAccount).addUserToChat(chat_id, user, info, param != null ? Utilities.parseInt(param) : 0, null, ProfileActivity.this)); if (info != null && info.participants != null) { SparseArray users = new SparseArray<>(); for (int a = 0; a < info.participants.participants.size(); a++) { @@ -1740,16 +1539,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } else if (id == NotificationCenter.encryptedChatCreated) { if (creatingChat) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); - TLRPC.EncryptedChat encryptedChat = (TLRPC.EncryptedChat) args[0]; - Bundle args2 = new Bundle(); - args2.putInt("enc_id", encryptedChat.id); - presentFragment(new ChatActivity(args2), true); - } + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + TLRPC.EncryptedChat encryptedChat = (TLRPC.EncryptedChat) args[0]; + Bundle args2 = new Bundle(); + args2.putInt("enc_id", encryptedChat.id); + presentFragment(new ChatActivity(args2), true); }); } } else if (id == NotificationCenter.encryptedChatUpdated) { @@ -1763,7 +1559,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } else if (id == NotificationCenter.blockedUsersDidLoaded) { boolean oldValue = userBlocked; - userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.contains(user_id); + userBlocked = MessagesController.getInstance(currentAccount).blockedUsers.indexOfKey(user_id) >= 0; if (oldValue != userBlocked) { createActionBarMenu(); } @@ -2059,12 +1855,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); animatorSet.setInterpolator(new DecelerateInterpolator()); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - animatorSet.start(); - } - }, 50); + AndroidUtilities.runOnUIThread(animatorSet::start, 50); return animatorSet; } return null; @@ -2085,48 +1876,45 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } try { - Collections.sort(sortedUsers, new Comparator() { - @Override - public int compare(Integer lhs, Integer rhs) { - TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(info.participants.participants.get(rhs).user_id); - TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(info.participants.participants.get(lhs).user_id); - int status1 = 0; - int status2 = 0; - if (user1 != null && user1.status != null) { - if (user1.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - status1 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; - } else { - status1 = user1.status.expires; - } + Collections.sort(sortedUsers, (lhs, rhs) -> { + TLRPC.User user1 = MessagesController.getInstance(currentAccount).getUser(info.participants.participants.get(rhs).user_id); + TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(info.participants.participants.get(lhs).user_id); + int status1 = 0; + int status2 = 0; + if (user1 != null && user1.status != null) { + if (user1.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + status1 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; + } else { + status1 = user1.status.expires; } - if (user2 != null && user2.status != null) { - if (user2.id == UserConfig.getInstance(currentAccount).getClientUserId()) { - status2 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; - } else { - status2 = user2.status.expires; - } + } + if (user2 != null && user2.status != null) { + if (user2.id == UserConfig.getInstance(currentAccount).getClientUserId()) { + status2 = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + 50000; + } else { + status2 = user2.status.expires; } - if (status1 > 0 && status2 > 0) { - if (status1 > status2) { - return 1; - } else if (status1 < status2) { - return -1; - } - return 0; - } else if (status1 < 0 && status2 < 0) { - if (status1 > status2) { - return 1; - } else if (status1 < status2) { - return -1; - } - return 0; - } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { - return -1; - } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { + } + if (status1 > 0 && status2 > 0) { + if (status1 > status2) { return 1; + } else if (status1 < status2) { + return -1; } return 0; + } else if (status1 < 0 && status2 < 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { + return -1; + } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { + return 1; } + return 0; }); } catch (Exception e) { FileLog.e(e); @@ -2701,22 +2489,19 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. break; case 8: view = new AboutLinkCell(mContext); - ((AboutLinkCell) view).setDelegate(new AboutLinkCell.AboutLinkCellDelegate() { - @Override - public void didPressUrl(String url) { - if (url.startsWith("@")) { - MessagesController.getInstance(currentAccount).openByUserName(url.substring(1), ProfileActivity.this, 0); - } else if (url.startsWith("#")) { - DialogsActivity fragment = new DialogsActivity(null); - fragment.setSearchString(url); - presentFragment(fragment); - } else if (url.startsWith("/")) { - if (parentLayout.fragmentsStack.size() > 1) { - BaseFragment previousFragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2); - if (previousFragment instanceof ChatActivity) { - finishFragment(); - ((ChatActivity) previousFragment).chatActivityEnterView.setCommand(null, url, false, false); - } + ((AboutLinkCell) view).setDelegate(url -> { + if (url.startsWith("@")) { + MessagesController.getInstance(currentAccount).openByUserName(url.substring(1), ProfileActivity.this, 0); + } else if (url.startsWith("#")) { + DialogsActivity fragment = new DialogsActivity(null); + fragment.setSearchString(url); + presentFragment(fragment); + } else if (url.startsWith("/")) { + if (parentLayout.fragmentsStack.size() > 1) { + BaseFragment previousFragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2); + if (previousFragment instanceof ChatActivity) { + finishFragment(); + ((ChatActivity) previousFragment).chatActivityEnterView.setCommand(null, url, false, false); } } } @@ -2861,7 +2646,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (enabled && custom) { val = LocaleController.getString("NotificationsCustom", R.string.NotificationsCustom); } else { - val = enabled ? LocaleController.getString("NotificationsOn", R.string.NotificationsOn) : LocaleController.getString("NotificationsOff", R.string.NotificationsOff); + if (hasOverride) { + val = enabled ? LocaleController.getString("NotificationsOn", R.string.NotificationsOn) : LocaleController.getString("NotificationsOff", R.string.NotificationsOff); + } else { + val = enabled ? LocaleController.getString("NotificationsDefaultOn", R.string.NotificationsDefaultOn) : LocaleController.getString("NotificationsDefaultOff", R.string.NotificationsDefaultOff); + } } } if (val != null) { @@ -2999,16 +2788,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override public ThemeDescription[] getThemeDescriptions() { - ThemeDescription.ThemeDescriptionDelegate cellDelegate = new ThemeDescription.ThemeDescriptionDelegate() { - @Override - public void didSetColor() { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof UserCell) { - ((UserCell) child).update(0); - } + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof UserCell) { + ((UserCell) child).update(0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index ee0b90a04..609e7e987 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -13,7 +13,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.media.Ringtone; @@ -334,30 +333,21 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi FileLog.e(e); } } else if (position == vibrateRow) { - showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, false, false, new Runnable() { - @Override - public void run() { - if (adapter != null) { - adapter.notifyItemChanged(vibrateRow); - } + showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, false, false, () -> { + if (adapter != null) { + adapter.notifyItemChanged(vibrateRow); } })); } else if (position == callsVibrateRow) { - showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, "calls_vibrate_", new Runnable() { - @Override - public void run() { - if (adapter != null) { - adapter.notifyItemChanged(callsVibrateRow); - } + showDialog(AlertsCreator.createVibrationSelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, "calls_vibrate_", () -> { + if (adapter != null) { + adapter.notifyItemChanged(callsVibrateRow); } })); } else if (position == priorityRow) { - showDialog(AlertsCreator.createPrioritySelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, false, false, new Runnable() { - @Override - public void run() { - if (adapter != null) { - adapter.notifyItemChanged(priorityRow); - } + showDialog(AlertsCreator.createPrioritySelectDialog(getParentActivity(), ProfileNotificationsActivity.this, dialog_id, false, false, () -> { + if (adapter != null) { + adapter.notifyItemChanged(priorityRow); } })); } else if (position == smartRow) { @@ -416,49 +406,40 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi } }); list.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(8)); - list.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (position < 0 || position >= 100) { - return; - } - int notifyMaxCount = position % 10 + 1; - int notifyDelay = position / 10 + 1; - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("smart_max_count_" + dialog_id, notifyMaxCount).commit(); - preferences.edit().putInt("smart_delay_" + dialog_id, notifyDelay * 60).commit(); - if (adapter != null) { - adapter.notifyItemChanged(smartRow); - } - dismissCurrentDialig(); + list.setOnItemClickListener((view1, position1) -> { + if (position1 < 0 || position1 >= 100) { + return; } + int notifyMaxCount1 = position1 % 10 + 1; + int notifyDelay1 = position1 / 10 + 1; + SharedPreferences preferences1 = MessagesController.getNotificationsSettings(currentAccount); + preferences1.edit().putInt("smart_max_count_" + dialog_id, notifyMaxCount1).commit(); + preferences1.edit().putInt("smart_delay_" + dialog_id, notifyDelay1 * 60).commit(); + if (adapter != null) { + adapter.notifyItemChanged(smartRow); + } + dismissCurrentDialig(); }); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("SmartNotificationsAlert", R.string.SmartNotificationsAlert)); builder.setView(list); builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.setNegativeButton(LocaleController.getString("SmartNotificationsDisabled", R.string.SmartNotificationsDisabled), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("smart_max_count_" + dialog_id, 0).commit(); - if (adapter != null) { - adapter.notifyItemChanged(smartRow); - } - dismissCurrentDialig(); + builder.setNegativeButton(LocaleController.getString("SmartNotificationsDisabled", R.string.SmartNotificationsDisabled), (dialog, which) -> { + SharedPreferences preferences12 = MessagesController.getNotificationsSettings(currentAccount); + preferences12.edit().putInt("smart_max_count_" + dialog_id, 0).commit(); + if (adapter != null) { + adapter.notifyItemChanged(smartRow); } + dismissCurrentDialig(); }); showDialog(builder.create()); } else if (position == colorRow) { if (getParentActivity() == null) { return; } - showDialog(AlertsCreator.createColorSelectDialog(getParentActivity(), dialog_id, false, false, new Runnable() { - @Override - public void run() { - if (adapter != null) { - adapter.notifyItemChanged(colorRow); - } + showDialog(AlertsCreator.createColorSelectDialog(getParentActivity(), dialog_id, false, false, () -> { + if (adapter != null) { + adapter.notifyItemChanged(colorRow); } })); } else if (position == popupEnabledRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index 99a93de9d..e0f95c9c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -40,6 +40,10 @@ import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -50,9 +54,6 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; -import org.telegram.messenger.exoplayer2.C; -import org.telegram.messenger.exoplayer2.ExoPlayer; -import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 78b479bfa..dead41ec9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -15,7 +15,6 @@ import android.animation.ObjectAnimator; import android.animation.StateListAnimator; import android.annotation.SuppressLint; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; @@ -67,9 +66,7 @@ import org.telegram.messenger.browser.Browser; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.FileLog; import org.telegram.messenger.MessagesController; @@ -102,6 +99,7 @@ import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.URLSpanNoUnderline; +import org.telegram.ui.Components.voip.VoIPHelper; import java.io.File; import java.util.ArrayList; @@ -157,8 +155,6 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter private int sendLogsRow; private int clearLogsRow; private int switchBackendButtonRow; - private int dumpCallStatsRow; - private int forceTcpInCallsRow; private int versionRow; private int contactsSectionRow; private int contactsReimportRow; @@ -221,55 +217,46 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter super.onFragmentCreate(); imageUpdater.parentFragment = this; - imageUpdater.delegate = new ImageUpdater.ImageUpdaterDelegate() { - @Override - public void didUploadedPhoto(TLRPC.InputFile file, TLRPC.PhotoSize small, TLRPC.PhotoSize big, TLRPC.TL_secureFile secureFile) { - TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); - req.file = file; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user == null) { - user = UserConfig.getInstance(currentAccount).getCurrentUser(); - if (user == null) { - return; - } - MessagesController.getInstance(currentAccount).putUser(user, false); - } else { - UserConfig.getInstance(currentAccount).setCurrentUser(user); - } - TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; - ArrayList sizes = photo.photo.sizes; - TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100); - TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000); - user.photo = new TLRPC.TL_userProfilePhoto(); - user.photo.photo_id = photo.photo.id; - if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - if (bigSize != null) { - user.photo.photo_big = bigSize.location; - } else if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); - ArrayList users = new ArrayList<>(); - users.add(user); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); - UserConfig.getInstance(currentAccount).saveConfig(true); - } - }); + imageUpdater.delegate = (file, small, big, secureFile) -> { + TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); + req.file = file; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user == null) { + user = UserConfig.getInstance(currentAccount).getCurrentUser(); + if (user == null) { + return; } + MessagesController.getInstance(currentAccount).putUser(user, false); + } else { + UserConfig.getInstance(currentAccount).setCurrentUser(user); } - }); - } + TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; + ArrayList sizes = photo.photo.sizes; + TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100); + TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000); + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photo.photo.id; + if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + if (bigSize != null) { + user.photo.photo_big = bigSize.location; + } else if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); + UserConfig.getInstance(currentAccount).saveConfig(true); + }); + } + }); }; NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.featuredStickersDidLoaded); @@ -313,14 +300,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (BuildVars.LOGS_ENABLED) { sendLogsRow = rowCount++; clearLogsRow = rowCount++; - dumpCallStatsRow = rowCount++; } else { sendLogsRow = -1; clearLogsRow = -1; - dumpCallStatsRow = -1; } if (BuildVars.DEBUG_VERSION) { - forceTcpInCallsRow = rowCount++; switchBackendButtonRow = rowCount++; } else { switchBackendButtonRow = -1; @@ -375,12 +359,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("AreYouSureLogout", R.string.AreYouSureLogout)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - MessagesController.getInstance(currentAccount).performLogout(1); - } - }); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> MessagesController.getInstance(currentAccount).performLogout(1)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } @@ -451,17 +430,14 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter numberPicker.setMaxValue(30); numberPicker.setValue(SharedConfig.fontSize); builder.setView(numberPicker); - builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("fons_size", numberPicker.getValue()); - SharedConfig.fontSize = numberPicker.getValue(); - editor.commit(); - if (listAdapter != null) { - listAdapter.notifyItemChanged(position); - } + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), (dialog, which) -> { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("fons_size", numberPicker.getValue()); + SharedConfig.fontSize = numberPicker.getValue(); + editor.commit(); + if (listAdapter != null) { + listAdapter.notifyItemChanged(position); } }); showDialog(builder.create()); @@ -510,12 +486,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setView(message); builder.setTitle(LocaleController.getString("AskAQuestion", R.string.AskAQuestion)); - builder.setPositiveButton(LocaleController.getString("AskButton", R.string.AskButton), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - performAskAQuestion(); - } - }); + builder.setPositiveButton(LocaleController.getString("AskButton", R.string.AskButton), (dialogInterface, i) -> performAskAQuestion()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else if (position == sendLogsRow) { @@ -571,14 +542,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - SharedConfig.pushAuthKey = null; - SharedConfig.pushAuthKeyId = null; - SharedConfig.saveConfig(); - ConnectionsManager.getInstance(currentAccount).switchBackend(); - } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + SharedConfig.pushAuthKey = null; + SharedConfig.pushAuthKeyId = null; + SharedConfig.saveConfig(); + ConnectionsManager.getInstance(currentAccount).switchBackend(); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); @@ -598,16 +566,13 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter LocaleController.getString("Default", R.string.Default), LocaleController.getString("SortFirstName", R.string.SortFirstName), LocaleController.getString("SortLastName", R.string.SortLastName) - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("sortContactsBy", which); - editor.commit(); - if (listAdapter != null) { - listAdapter.notifyItemChanged(position); - } + }, (dialog, which) -> { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("sortContactsBy", which); + editor.commit(); + if (listAdapter != null) { + listAdapter.notifyItemChanged(position); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -649,60 +614,36 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter linearLayout.addView(checkBoxCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); checkBoxCell.setText(name, "", maskValues[a], true); checkBoxCell.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - checkBoxCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBoxCell cell = (CheckBoxCell) v; - int num = (Integer) cell.getTag(); - maskValues[num] = !maskValues[num]; - cell.setChecked(maskValues[num], true); - } + checkBoxCell.setOnClickListener(v -> { + CheckBoxCell cell = (CheckBoxCell) v; + int num = (Integer) cell.getTag(); + maskValues[num] = !maskValues[num]; + cell.setChecked(maskValues[num], true); }); } BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 1); cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); cell.setTextAndIcon(LocaleController.getString("Save", R.string.Save).toUpperCase(), 0); cell.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2)); - cell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - } - } catch (Exception e) { - FileLog.e(e); - } - SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.putBoolean("allowBigEmoji", SharedConfig.allowBigEmoji = maskValues[0]); - editor.putBoolean("useSystemEmoji", SharedConfig.useSystemEmoji = maskValues[1]); - editor.commit(); - if (listAdapter != null) { - listAdapter.notifyItemChanged(position); + cell.setOnClickListener(v -> { + try { + if (visibleDialog != null) { + visibleDialog.dismiss(); } + } catch (Exception e) { + FileLog.e(e); + } + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putBoolean("allowBigEmoji", SharedConfig.allowBigEmoji = maskValues[0]); + editor.putBoolean("useSystemEmoji", SharedConfig.useSystemEmoji = maskValues[1]); + editor.commit(); + if (listAdapter != null) { + listAdapter.notifyItemChanged(position); } }); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); builder.setCustomView(linearLayout); showDialog(builder.create()); - } else if (position == dumpCallStatsRow) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean dump = preferences.getBoolean("dbg_dump_call_stats", false); - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean("dbg_dump_call_stats", !dump); - editor.commit(); - if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(!dump); - } - }else if (position == forceTcpInCallsRow) { - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean dump = preferences.getBoolean("dbg_force_tcp_in_calls", false); - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean("dbg_force_tcp_in_calls", !dump); - editor.commit(); - if (view instanceof TextCheckCell) { - ((TextCheckCell) view).setChecked(!dump); - } } } }); @@ -727,35 +668,35 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter BuildVars.LOGS_ENABLED ? LocaleController.getString("DebugMenuDisableLogs", R.string.DebugMenuDisableLogs) : LocaleController.getString("DebugMenuEnableLogs", R.string.DebugMenuEnableLogs), SharedConfig.inappCamera ? LocaleController.getString("DebugMenuDisableCamera", R.string.DebugMenuDisableCamera) : LocaleController.getString("DebugMenuEnableCamera", R.string.DebugMenuEnableCamera), LocaleController.getString("DebugMenuClearMediaCache", R.string.DebugMenuClearMediaCache), + LocaleController.getString("DebugMenuCallSettings", R.string.DebugMenuCallSettings), null, BuildVars.DEBUG_PRIVATE_VERSION ? "Check for app updates" : null }; - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == 0) { - UserConfig.getInstance(currentAccount).syncContacts = true; - UserConfig.getInstance(currentAccount).saveConfig(false); - ContactsController.getInstance(currentAccount).forceImportContacts(); - } else if (which == 1) { - ContactsController.getInstance(currentAccount).loadContacts(false, 0); - } else if (which == 2) { - ContactsController.getInstance(currentAccount).resetImportedContacts(); - } else if (which == 3) { - MessagesController.getInstance(currentAccount).forceResetDialogs(); - } else if (which == 4) { - BuildVars.LOGS_ENABLED = !BuildVars.LOGS_ENABLED; - SharedPreferences sharedPreferences = ApplicationLoader.applicationContext.getSharedPreferences("systemConfig", Context.MODE_PRIVATE); - sharedPreferences.edit().putBoolean("logsEnabled", BuildVars.LOGS_ENABLED).commit(); - } else if (which == 5) { - SharedConfig.toggleInappCamera(); - } else if (which == 6) { - MessagesStorage.getInstance(currentAccount).clearSentMedia(); - } else if (which == 7) { - SharedConfig.toggleRoundCamera16to9(); - } else if (which == 8) { - ((LaunchActivity) getParentActivity()).checkAppUpdate(true); - } + builder.setItems(items, (dialog, which) -> { + if (which == 0) { + UserConfig.getInstance(currentAccount).syncContacts = true; + UserConfig.getInstance(currentAccount).saveConfig(false); + ContactsController.getInstance(currentAccount).forceImportContacts(); + } else if (which == 1) { + ContactsController.getInstance(currentAccount).loadContacts(false, 0); + } else if (which == 2) { + ContactsController.getInstance(currentAccount).resetImportedContacts(); + } else if (which == 3) { + MessagesController.getInstance(currentAccount).forceResetDialogs(); + } else if (which == 4) { + BuildVars.LOGS_ENABLED = !BuildVars.LOGS_ENABLED; + SharedPreferences sharedPreferences = ApplicationLoader.applicationContext.getSharedPreferences("systemConfig", Context.MODE_PRIVATE); + sharedPreferences.edit().putBoolean("logsEnabled", BuildVars.LOGS_ENABLED).commit(); + } else if (which == 5) { + SharedConfig.toggleInappCamera(); + } else if (which == 6) { + MessagesStorage.getInstance(currentAccount).clearSentMedia(); + } else if (which == 7) { + VoIPHelper.showCallDebugSettings(getParentActivity()); + } else if (which == 8) { + SharedConfig.toggleRoundCamera16to9(); + } else if (which == 9) { + ((LaunchActivity) getParentActivity()).checkAppUpdate(true); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -789,14 +730,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter avatarImage.setPivotX(0); avatarImage.setPivotY(0); frameLayout.addView(avatarImage, LayoutHelper.createFrame(42, 42, Gravity.TOP | Gravity.LEFT, 64, 0, 0, 0)); - avatarImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user != null && user.photo != null && user.photo.photo_big != null) { - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(user.photo.photo_big, provider); - } + avatarImage.setOnClickListener(v -> { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user != null && user.photo != null && user.photo.photo_big != null) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(user.photo.photo_big, provider); } }); @@ -850,46 +788,40 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter }); } frameLayout.addView(writeButton, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, Gravity.RIGHT | Gravity.TOP, 0, 0, 16, 0)); - writeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - - CharSequence[] items; - - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user == null) { - user = UserConfig.getInstance(currentAccount).getCurrentUser(); - } - if (user == null) { - return; - } - boolean fullMenu = false; - if (user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty)) { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; - fullMenu = true; - } else { - items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; - } - - final boolean full = fullMenu; - builder.setItems(items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - imageUpdater.openCamera(); - } else if (i == 1) { - imageUpdater.openGallery(); - } else if (i == 2) { - MessagesController.getInstance(currentAccount).deleteUserPhoto(null); - } - } - }); - showDialog(builder.create()); + writeButton.setOnClickListener(v -> { + if (getParentActivity() == null) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + + CharSequence[] items; + + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user == null) { + user = UserConfig.getInstance(currentAccount).getCurrentUser(); + } + if (user == null) { + return; + } + boolean fullMenu = false; + if (user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty)) { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; + fullMenu = true; + } else { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; + } + + final boolean full = fullMenu; + builder.setItems(items, (dialogInterface, i) -> { + if (i == 0) { + imageUpdater.openCamera(); + } else if (i == 1) { + imageUpdater.openGallery(); + } else if (i == 2) { + MessagesController.getInstance(currentAccount).deleteUserPhoto(null); + } + }); + showDialog(builder.create()); }); needLayout(); @@ -917,6 +849,49 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter return fragmentView; } + /*private void test(boolean argon) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + EditText editText = new EditText(getParentActivity()); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + if (argon) { + editText.setText("5"); + } else { + editText.setText("100000"); + } + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setGravity(Gravity.CENTER); + editText.setInputType(InputType.TYPE_CLASS_NUMBER); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setBackgroundDrawable(Theme.createEditTextDrawable(getParentActivity(), true)); + editText.setPadding(0, 0, 0, 0); + builder.setView(editText); + builder.setMessage("Enter iterations count:"); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + long time = SystemClock.elapsedRealtime(); + int result; + if (argon) { + result = Utilities.argon2(Utilities.parseInt(editText.getText().toString())); + } else { + result = Utilities.pbkdf2(Utilities.parseInt(editText.getText().toString())); + } + time = SystemClock.elapsedRealtime() - time; + AlertsCreator.showSimpleAlert(SettingsActivity.this, "result = " + result + ", elapsed time = " + time + "ms"); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) editText.getLayoutParams(); + if (layoutParams != null) { + if (layoutParams instanceof FrameLayout.LayoutParams) { + ((FrameLayout.LayoutParams) layoutParams).gravity = Gravity.CENTER_HORIZONTAL; + } + layoutParams.rightMargin = layoutParams.leftMargin = AndroidUtilities.dp(24); + layoutParams.height = AndroidUtilities.dp(36); + editText.setLayoutParams(layoutParams); + } + editText.setSelection(0, editText.getText().length()); + }*/ + private void performAskAQuestion() { final SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); int uid = preferences.getInt("support_id", 0); @@ -950,48 +925,39 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter progressDialog.setCancelable(false); progressDialog.show(); TLRPC.TL_help_getSupport req = new TLRPC.TL_help_getSupport(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (error == null) { - final TLRPC.TL_help_support res = (TLRPC.TL_help_support) response; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("support_id", res.user.id); - SerializedData data = new SerializedData(); - res.user.serializeToStream(data); - editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT)); - editor.commit(); - data.cleanup(); - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - ArrayList users = new ArrayList<>(); - users.add(res.user); - MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, true, true); - MessagesController.getInstance(currentAccount).putUser(res.user, false); - Bundle args = new Bundle(); - args.putInt("user_id", res.user.id); - presentFragment(new ChatActivity(args)); - } - }); - } else { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - try { - progressDialog.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - }); - } + final TLRPC.TL_help_support res = (TLRPC.TL_help_support) response; + AndroidUtilities.runOnUIThread(() -> { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("support_id", res.user.id); + SerializedData data = new SerializedData(); + res.user.serializeToStream(data); + editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT)); + editor.commit(); + data.cleanup(); + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + ArrayList users = new ArrayList<>(); + users.add(res.user); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, true, true); + MessagesController.getInstance(currentAccount).putUser(res.user, false); + Bundle args = new Bundle(); + args.putInt("user_id", res.user.id); + presentFragment(new ChatActivity(args)); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + }); } }); } else { @@ -1300,10 +1266,6 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter textCell.setTextAndValueAndCheck(LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), LocaleController.getString("ChromeCustomTabsInfo", R.string.ChromeCustomTabsInfo), SharedConfig.customTabs, false, true); } else if (position == directShareRow) { textCell.setTextAndValueAndCheck(LocaleController.getString("DirectShare", R.string.DirectShare), LocaleController.getString("DirectShareInfo", R.string.DirectShareInfo), SharedConfig.directShare, false, true); - } else if (position == dumpCallStatsRow) { - textCell.setTextAndCheck("Dump detailed call stats", preferences.getBoolean("dbg_dump_call_stats", false), true); - } else if (position == forceTcpInCallsRow) { - textCell.setTextAndValueAndCheck("Force TCP in calls", "This disables UDP", preferences.getBoolean("dbg_force_tcp_in_calls", false), false, true); } break; } @@ -1330,7 +1292,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } else { value = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); } - textCell.setTextAndValue(value, LocaleController.getString("Phone", R.string.Phone), true); + textCell.setTextAndValue(value, LocaleController.getString("TapToChangePhone", R.string.TapToChangePhone), true); } else if (position == usernameRow) { TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); String value; @@ -1365,7 +1327,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter position == clearLogsRow || position == languageRow || position == usernameRow || position == bioRow || position == switchBackendButtonRow || position == telegramFaqRow || position == contactsSortRow || position == contactsReimportRow || position == saveToGalleryRow || position == stickersRow || position == raiseToSpeakRow || position == privacyPolicyRow || position == customTabsRow || position == directShareRow || position == versionRow || - position == emojiRow || position == dataRow || position == themeRow || position == dumpCallStatsRow || position == forceTcpInCallsRow; + position == emojiRow || position == dataRow || position == themeRow; } @Override @@ -1441,7 +1403,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } if (position == settingsSectionRow || position == supportSectionRow || position == messagesSectionRow || position == contactsSectionRow) { return 1; - } else if (position == enableAnimationsRow || position == sendByEnterRow || position == saveToGalleryRow || position == autoplayGifsRow || position == raiseToSpeakRow || position == customTabsRow || position == directShareRow || position == dumpCallStatsRow || position == forceTcpInCallsRow) { + } else if (position == enableAnimationsRow || position == sendByEnterRow || position == saveToGalleryRow || position == autoplayGifsRow || position == raiseToSpeakRow || position == customTabsRow || position == directShareRow) { return 3; } else if (position == notificationRow || position == themeRow || position == backgroundRow || position == askQuestionRow || position == sendLogsRow || position == privacyRow || position == clearLogsRow || position == switchBackendButtonRow || position == telegramFaqRow || position == contactsReimportRow || position == textSizeRow || position == languageRow || position == contactsSortRow || position == stickersRow || position == privacyPolicyRow || position == emojiRow || position == dataRow) { return 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java index cd21c60d1..515518acb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java @@ -10,7 +10,6 @@ package org.telegram.ui; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.graphics.Typeface; import android.os.Vibrator; import android.text.InputType; @@ -19,7 +18,6 @@ import android.text.method.PasswordTransformationMethod; import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; -import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -36,13 +34,13 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; +import org.telegram.messenger.SRPHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.ActionBar; @@ -54,11 +52,14 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import java.math.BigInteger; + public class TwoStepVerificationActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListAdapter listAdapter; @@ -82,10 +83,9 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific private boolean destroyed; private boolean paused; private boolean waitingForEmail; - private TLRPC.account_Password currentPassword; + private TLRPC.TL_account_password currentPassword; private boolean passwordEntered = true; private byte[] currentPasswordHash = new byte[0]; - private byte[] currentSecretSalt; private long currentSecretId; private byte[] currentSecret; private Runnable shortPollRunnable; @@ -123,7 +123,7 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } } - protected void setRecoveryParams(TLRPC.account_Password password) { + protected void setRecoveryParams(TLRPC.TL_account_password password) { currentPassword = password; passwordSetState = 4; } @@ -212,15 +212,12 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific passwordEditText.setCursorSize(AndroidUtilities.dp(20)); passwordEditText.setCursorWidth(1.5f); linearLayout.addView(passwordEditText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 40, 32, 40, 0)); - passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT || i == EditorInfo.IME_ACTION_DONE) { - processDone(); - return true; - } - return false; + passwordEditText.setOnEditorActionListener((textView, i, keyEvent) -> { + if (i == EditorInfo.IME_ACTION_NEXT || i == EditorInfo.IME_ACTION_DONE) { + processDone(); + return true; } + return false; }); passwordEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() { public boolean onPrepareActionMode(ActionMode mode, Menu menu) { @@ -257,94 +254,71 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific bottomButton.setText(LocaleController.getString("YourEmailSkip", R.string.YourEmailSkip)); bottomButton.setPadding(0, AndroidUtilities.dp(10), 0, 0); linearLayout2.addView(bottomButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.BOTTOM, 40, 0, 40, 14)); - bottomButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (type == 0) { - if (currentPassword.has_recovery) { - needShowProgress(); - TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); - fragment.currentPassword = currentPassword; - fragment.currentPassword.email_unconfirmed_pattern = res.email_pattern; - fragment.currentSecretId = currentSecretId; - fragment.currentSecret = currentSecret; - fragment.currentSecretSalt = currentSecretSalt; - fragment.passwordSetState = 4; - presentFragment(fragment); - } - }); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } else { - if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + bottomButton.setOnClickListener(v -> { + if (type == 0) { + if (currentPassword.has_recovery) { + needShowProgress(); + TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (error == null) { + final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("RestoreEmailSent", R.string.RestoreEmailSent, res.email_pattern)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); + fragment.currentPassword = currentPassword; + fragment.currentPassword.email_unconfirmed_pattern = res.email_pattern; + fragment.currentSecretId = currentSecretId; + fragment.currentSecret = currentSecret; + fragment.passwordSetState = 4; + presentFragment(fragment); + }); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); + } + } else { + if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); - } else { - if (getParentActivity() == null) { - return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setNegativeButton(LocaleController.getString("RestorePasswordResetAccount", R.string.RestorePasswordResetAccount), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Browser.openUrl(getParentActivity(), "https://telegram.org/deactivate?phone=" + UserConfig.getInstance(currentAccount).getClientPhone()); - } - }); - builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); - builder.setMessage(LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); - showDialog(builder.create()); - } + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { - if (passwordSetState == 4) { - showAlertWithText(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle), LocaleController.getString("RestoreEmailTroubleText", R.string.RestoreEmailTroubleText)); - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("YourEmailSkipWarningText", R.string.YourEmailSkipWarningText)); - builder.setTitle(LocaleController.getString("YourEmailSkipWarning", R.string.YourEmailSkipWarning)); - builder.setPositiveButton(LocaleController.getString("YourEmailSkip", R.string.YourEmailSkip), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - email = ""; - setNewPassword(false); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + if (getParentActivity() == null) { + return; } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setNegativeButton(LocaleController.getString("RestorePasswordResetAccount", R.string.RestorePasswordResetAccount), (dialog, which) -> Browser.openUrl(getParentActivity(), "https://telegram.org/deactivate?phone=" + UserConfig.getInstance(currentAccount).getClientPhone())); + builder.setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)); + builder.setMessage(LocaleController.getString("RestorePasswordNoEmailText", R.string.RestorePasswordNoEmailText)); + showDialog(builder.create()); + } + } else { + if (passwordSetState == 4) { + showAlertWithText(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle), LocaleController.getString("RestoreEmailTroubleText", R.string.RestoreEmailTroubleText)); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("YourEmailSkipWarningText", R.string.YourEmailSkipWarningText)); + builder.setTitle(LocaleController.getString("YourEmailSkipWarning", R.string.YourEmailSkipWarning)); + builder.setPositiveButton(LocaleController.getString("YourEmailSkip", R.string.YourEmailSkip), (dialogInterface, i) -> { + email = ""; + setNewPassword(false); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); } } }); @@ -360,44 +334,34 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific listView.setVerticalScrollBarEnabled(false); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setAdapter(listAdapter = new ListAdapter(context)); - listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (position == setPasswordRow || position == changePasswordRow) { - TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); - fragment.currentPasswordHash = currentPasswordHash; - fragment.currentPassword = currentPassword; - fragment.currentSecretId = currentSecretId; - fragment.currentSecret = currentSecret; - fragment.currentSecretSalt = currentSecretSalt; - presentFragment(fragment); - } else if (position == setRecoveryEmailRow || position == changeRecoveryEmailRow) { - TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); - fragment.currentPasswordHash = currentPasswordHash; - fragment.currentPassword = currentPassword; - fragment.currentSecretId = currentSecretId; - fragment.currentSecret = currentSecret; - fragment.currentSecretSalt = currentSecretSalt; - fragment.emailOnly = true; - fragment.passwordSetState = 3; - presentFragment(fragment); - } else if (position == turnPasswordOffRow || position == abortPasswordRow) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - String text = LocaleController.getString("TurnPasswordOffQuestion", R.string.TurnPasswordOffQuestion); - if (currentPassword.has_secure_values) { - text += "\n\n" + LocaleController.getString("TurnPasswordOffPassport", R.string.TurnPasswordOffPassport); - } - builder.setMessage(text); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - setNewPassword(true); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + listView.setOnItemClickListener((view, position) -> { + if (position == setPasswordRow || position == changePasswordRow) { + TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); + fragment.currentPasswordHash = currentPasswordHash; + fragment.currentPassword = currentPassword; + fragment.currentSecretId = currentSecretId; + fragment.currentSecret = currentSecret; + presentFragment(fragment); + } else if (position == setRecoveryEmailRow || position == changeRecoveryEmailRow) { + TwoStepVerificationActivity fragment = new TwoStepVerificationActivity(currentAccount, 1); + fragment.currentPasswordHash = currentPasswordHash; + fragment.currentPassword = currentPassword; + fragment.currentSecretId = currentSecretId; + fragment.currentSecret = currentSecret; + fragment.emailOnly = true; + fragment.passwordSetState = 3; + presentFragment(fragment); + } else if (position == turnPasswordOffRow || position == abortPasswordRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + String text = LocaleController.getString("TurnPasswordOffQuestion", R.string.TurnPasswordOffQuestion); + if (currentPassword.has_secure_values) { + text += "\n\n" + LocaleController.getString("TurnPasswordOffPassport", R.string.TurnPasswordOffPassport); } + builder.setMessage(text); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> setNewPassword(true)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); } }); @@ -409,6 +373,14 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific setPasswordSetState(passwordSetState); } + if (passwordEntered && type != 1) { + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + fragmentView.setTag(Theme.key_windowBackgroundGray); + } else { + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + fragmentView.setTag(Theme.key_windowBackgroundWhite); + } + return fragmentView; } @@ -440,13 +412,10 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific super.onResume(); paused = false; if (type == 1) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (passwordEditText != null) { - passwordEditText.requestFocus(); - AndroidUtilities.showKeyboard(passwordEditText); - } + AndroidUtilities.runOnUIThread(() -> { + if (passwordEditText != null) { + passwordEditText.requestFocus(); + AndroidUtilities.showKeyboard(passwordEditText); } }, 200); } @@ -457,7 +426,7 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific closeAfterSet = value; } - public void setCurrentPasswordInfo(byte[] hash, TLRPC.account_Password password) { + public void setCurrentPasswordInfo(byte[] hash, TLRPC.TL_account_password password) { currentPasswordHash = hash; currentPassword = password; } @@ -469,6 +438,38 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } } + public static boolean canHandleCurrentPassword(TLRPC.TL_account_password password, boolean login) { + if (login) { + if (password.current_algo instanceof TLRPC.TL_passwordKdfAlgoUnknown) { + return false; + } + } else { + if (password.new_algo instanceof TLRPC.TL_passwordKdfAlgoUnknown || + password.current_algo instanceof TLRPC.TL_passwordKdfAlgoUnknown || + password.new_secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoUnknown) { + return false; + } + } + return true; + } + + public static void initPasswordNewAlgo(TLRPC.TL_account_password password) { + if (password.new_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) password.new_algo; + byte[] salt = new byte[algo.salt1.length + 32]; + Utilities.random.nextBytes(salt); + System.arraycopy(algo.salt1, 0, salt, 0, algo.salt1.length); + algo.salt1 = salt; + } + if (password.new_secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 algo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) password.new_secure_algo; + byte[] salt = new byte[algo.salt.length + 32]; + Utilities.random.nextBytes(salt); + System.arraycopy(algo.salt, 0, salt, 0, algo.salt.length); + algo.salt = salt; + } + } + private void loadPasswordInfo(final boolean silent) { if (!silent) { loading = true; @@ -477,56 +478,50 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } } TLRPC.TL_account_getPassword req = new TLRPC.TL_account_getPassword(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - loading = false; - if (error == null) { - if (!silent) { - passwordEntered = currentPassword != null || response instanceof TLRPC.TL_account_noPassword; - } - currentPassword = (TLRPC.account_Password) response; - waitingForEmail = currentPassword.email_unconfirmed_pattern.length() > 0; - byte[] salt = new byte[currentPassword.new_salt.length + 8]; - Utilities.random.nextBytes(salt); - System.arraycopy(currentPassword.new_salt, 0, salt, 0, currentPassword.new_salt.length); - currentPassword.new_salt = salt; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + loading = false; + currentPassword = (TLRPC.TL_account_password) response; + if (!canHandleCurrentPassword(currentPassword, false)) { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + return; + } + if (!silent) { + passwordEntered = currentPasswordHash != null && currentPasswordHash.length > 0 || !currentPassword.has_password; + } + waitingForEmail = !TextUtils.isEmpty(currentPassword.email_unconfirmed_pattern); + initPasswordNewAlgo(currentPassword); + if (!paused && closeAfterSet && currentPassword.has_password) { + TLRPC.PasswordKdfAlgo pendingCurrentAlgo = currentPassword.current_algo; + TLRPC.SecurePasswordKdfAlgo pendingNewSecureAlgo = currentPassword.new_secure_algo; + byte[] pendingSecureRandom = currentPassword.secure_random; + String pendingEmail = currentPassword.has_recovery ? "1" : null; + String pendingHint = currentPassword.hint != null ? currentPassword.hint : ""; - if (!paused && closeAfterSet && currentPassword instanceof TLRPC.TL_account_password) { - byte[] pendingCurrentSalt = currentPassword.current_salt; - byte[] pendingNewSecureSalt = currentPassword.new_secure_salt; - byte[] pendingSecureRandom = currentPassword.secure_random; - String pendingEmail = currentPassword.has_recovery ? "1" : null; - String pendingHint = currentPassword.hint; - - if (!waitingForEmail && pendingCurrentSalt != null) { - NotificationCenter.getInstance(currentAccount).removeObserver(TwoStepVerificationActivity.this, NotificationCenter.didSetTwoStepPassword); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, null, pendingCurrentSalt, pendingNewSecureSalt, pendingSecureRandom, pendingEmail, pendingHint, null, null); - finishFragment(); - } - } - } - if (type == 0 && !destroyed && shortPollRunnable == null) { - shortPollRunnable = new Runnable() { - @Override - public void run() { - if (shortPollRunnable == null) { - return; - } - loadPasswordInfo(true); - shortPollRunnable = null; - } - }; - AndroidUtilities.runOnUIThread(shortPollRunnable, 5000); - } - updateRows(); + if (!waitingForEmail && pendingCurrentAlgo != null) { + NotificationCenter.getInstance(currentAccount).removeObserver(TwoStepVerificationActivity.this, NotificationCenter.didSetTwoStepPassword); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, null, pendingCurrentAlgo, pendingNewSecureAlgo, pendingSecureRandom, pendingEmail, pendingHint, null, null); + finishFragment(); } - }); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + if (type == 0 && !destroyed && shortPollRunnable == null && !TextUtils.isEmpty(currentPassword.email_unconfirmed_pattern)) { + startShortpoll(); + } + updateRows(); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } + + private void startShortpoll() { + AndroidUtilities.cancelRunOnUIThread(shortPollRunnable); + shortPollRunnable = () -> { + if (shortPollRunnable == null) { + return; + } + loadPasswordInfo(true); + shortPollRunnable = null; + }; + AndroidUtilities.runOnUIThread(shortPollRunnable, 5000); } private void setPasswordSetState(int state) { @@ -536,10 +531,10 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific passwordSetState = state; if (passwordSetState == 0) { actionBar.setTitle(LocaleController.getString("YourPassword", R.string.YourPassword)); - if (currentPassword instanceof TLRPC.TL_account_noPassword) { - titleTextView.setText(LocaleController.getString("PleaseEnterFirstPassword", R.string.PleaseEnterFirstPassword)); - } else { + if (currentPassword.has_password) { titleTextView.setText(LocaleController.getString("PleaseEnterPassword", R.string.PleaseEnterPassword)); + } else { + titleTextView.setText(LocaleController.getString("PleaseEnterFirstPassword", R.string.PleaseEnterFirstPassword)); } passwordEditText.setImeOptions(EditorInfo.IME_ACTION_NEXT); passwordEditText.setTransformationMethod(PasswordTransformationMethod.getInstance()); @@ -571,7 +566,7 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific actionBar.setTitle(LocaleController.getString("PasswordRecovery", R.string.PasswordRecovery)); titleTextView.setText(LocaleController.getString("PasswordCode", R.string.PasswordCode)); bottomTextView.setText(LocaleController.getString("RestoreEmailSentInfo", R.string.RestoreEmailSentInfo)); - bottomButton.setText(LocaleController.formatString("RestoreEmailTrouble", R.string.RestoreEmailTrouble, currentPassword.email_unconfirmed_pattern)); + bottomButton.setText(LocaleController.formatString("RestoreEmailTrouble", R.string.RestoreEmailTrouble, currentPassword.email_unconfirmed_pattern != null ? currentPassword.email_unconfirmed_pattern : "")); passwordEditText.setImeOptions(EditorInfo.IME_ACTION_DONE); passwordEditText.setTransformationMethod(null); passwordEditText.setInputType(InputType.TYPE_CLASS_PHONE); @@ -595,16 +590,7 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific passwordEmailVerifyDetailRow = -1; shadowRow = -1; if (!loading && currentPassword != null) { - if (currentPassword instanceof TLRPC.TL_account_noPassword) { - if (waitingForEmail) { - passwordSetupDetailRow = rowCount++; - abortPasswordRow = rowCount++; - shadowRow = rowCount++; - } else { - setPasswordRow = rowCount++; - setPasswordDetailRow = rowCount++; - } - } else if (currentPassword instanceof TLRPC.TL_account_password) { + if (currentPassword.has_password) { changePasswordRow = rowCount++; turnPasswordOffRow = rowCount++; if (currentPassword.has_recovery) { @@ -617,6 +603,15 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } else { passwordEnabledDetailRow = rowCount++; } + } else { + if (waitingForEmail) { + passwordSetupDetailRow = rowCount++; + abortPasswordRow = rowCount++; + shadowRow = rowCount++; + } else { + setPasswordRow = rowCount++; + setPasswordDetailRow = rowCount++; + } } } @@ -635,6 +630,10 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific titleTextView.setVisibility(View.INVISIBLE); bottomTextView.setVisibility(View.INVISIBLE); bottomButton.setVisibility(View.INVISIBLE); + if (fragmentView != null) { + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + fragmentView.setTag(Theme.key_windowBackgroundGray); + } } } else { if (listView != null) { @@ -646,22 +645,23 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific if (passwordEditText != null) { doneItem.setVisibility(View.VISIBLE); passwordEditText.setVisibility(View.VISIBLE); + if (fragmentView != null) { + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + fragmentView.setTag(Theme.key_windowBackgroundWhite); + } titleTextView.setVisibility(View.VISIBLE); bottomButton.setVisibility(View.VISIBLE); bottomTextView.setVisibility(View.INVISIBLE); bottomButton.setText(LocaleController.getString("ForgotPassword", R.string.ForgotPassword)); - if (currentPassword.hint != null && currentPassword.hint.length() > 0) { + if (!TextUtils.isEmpty(currentPassword.hint)) { passwordEditText.setHint(currentPassword.hint); } else { passwordEditText.setHint(""); } - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (!isFinishing() && !destroyed && passwordEditText != null) { - passwordEditText.requestFocus(); - AndroidUtilities.showKeyboard(passwordEditText); - } + AndroidUtilities.runOnUIThread(() -> { + if (!isFinishing() && !destroyed && passwordEditText != null) { + passwordEditText.requestFocus(); + AndroidUtilities.showKeyboard(passwordEditText); } }, 200); } @@ -709,52 +709,37 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } private void setNewPassword(final boolean clear) { + final String password = firstPassword; final TLRPC.TL_account_updatePasswordSettings req = new TLRPC.TL_account_updatePasswordSettings(); - req.current_password_hash = currentPasswordHash; + if (currentPasswordHash == null || currentPasswordHash.length == 0) { + req.password = new TLRPC.TL_inputCheckPasswordEmpty(); + } req.new_settings = new TLRPC.TL_account_passwordInputSettings(); if (clear) { UserConfig.getInstance(currentAccount).resetSavedPassword(); - if (waitingForEmail && currentPassword instanceof TLRPC.TL_account_noPassword) { + currentSecret = null; + if (waitingForEmail && !currentPassword.has_password) { req.new_settings.flags = 2; req.new_settings.email = ""; - req.current_password_hash = new byte[0]; + req.password = new TLRPC.TL_inputCheckPasswordEmpty(); } else { req.new_settings.flags = 3; req.new_settings.hint = ""; req.new_settings.new_password_hash = new byte[0]; - req.new_settings.new_salt = new byte[0]; + req.new_settings.new_algo = new TLRPC.TL_passwordKdfAlgoUnknown(); req.new_settings.email = ""; } } else { - if (firstPassword != null && firstPassword.length() > 0) { - byte[] newPasswordBytes = AndroidUtilities.getStringBytes(firstPassword); - - byte[] new_salt = currentPassword.new_salt; - byte[] hash = new byte[new_salt.length * 2 + newPasswordBytes.length]; - System.arraycopy(new_salt, 0, hash, 0, new_salt.length); - System.arraycopy(newPasswordBytes, 0, hash, new_salt.length, newPasswordBytes.length); - System.arraycopy(new_salt, 0, hash, hash.length - new_salt.length, new_salt.length); + if (hint == null && currentPassword != null) { + hint = currentPassword.hint; + } + if (hint == null) { + hint = ""; + } + if (password != null) { req.new_settings.flags |= 1; req.new_settings.hint = hint; - req.new_settings.new_password_hash = Utilities.computeSHA256(hash, 0, hash.length); - req.new_settings.new_salt = new_salt; - - if (currentSecret != null && currentSecret.length == 32) { - byte[] passwordHash = Utilities.computeSHA512(currentSecretSalt, newPasswordBytes, currentSecretSalt); - byte[] key = new byte[32]; - System.arraycopy(passwordHash, 0, key, 0, 32); - byte[] iv = new byte[16]; - System.arraycopy(passwordHash, 32, iv, 0, 16); - - byte[] encryptedSecret = new byte[32]; - System.arraycopy(currentSecret, 0, encryptedSecret, 0, 32); - Utilities.aesCbcEncryptionByteArraySafe(encryptedSecret, key, iv, 0, encryptedSecret.length, 0, 1); - - req.new_settings.new_secure_secret = encryptedSecret; - req.new_settings.new_secure_salt = currentSecretSalt; - req.new_settings.new_secure_secret_id = currentSecretId; - req.new_settings.flags |= 4; - } + req.new_settings.new_algo = currentPassword.new_algo; } if (email.length() > 0) { req.new_settings.flags |= 2; @@ -762,103 +747,203 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } } needShowProgress(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null && response instanceof TLRPC.TL_boolTrue) { - if (clear) { - currentPassword = null; - currentPasswordHash = new byte[0]; - loadPasswordInfo(false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didRemovedTwoStepPassword); - updateRows(); - } else { - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, req.new_settings.new_password_hash, req.new_settings.new_salt, currentPassword.new_secure_salt, currentPassword.secure_random, email, hint, null, firstPassword); - finishFragment(); - } - }); - builder.setMessage(LocaleController.getString("YourPasswordSuccessText", R.string.YourPasswordSuccessText)); - builder.setTitle(LocaleController.getString("YourPasswordSuccess", R.string.YourPasswordSuccess)); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } - } else if (error != null) { - if (error.text.equals("EMAIL_UNCONFIRMED")) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (closeAfterSet) { - TwoStepVerificationActivity activity = new TwoStepVerificationActivity(currentAccount, 0); - activity.setCloseAfterSet(true); - parentLayout.addFragmentToStack(activity, parentLayout.fragmentsStack.size() - 1); - } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, req.new_settings.new_password_hash, req.new_settings.new_salt, currentPassword.new_secure_salt, currentPassword.secure_random, email, hint, email, firstPassword); - finishFragment(); - } - }); - builder.setMessage(LocaleController.getString("YourEmailAlmostThereText", R.string.YourEmailAlmostThereText)); - builder.setTitle(LocaleController.getString("YourEmailAlmostThere", R.string.YourEmailAlmostThere)); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } else { - if (error.text.equals("EMAIL_INVALID")) { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PasswordEmailInvalid", R.string.PasswordEmailInvalid)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } + Utilities.globalQueue.postRunnable(() -> { + if (req.password == null) { + req.password = getNewSrpPassword(); + } + + byte[] newPasswordBytes; + byte[] newPasswordHash; + if (!clear && password != null) { + newPasswordBytes = AndroidUtilities.getStringBytes(password); + if (currentPassword.new_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.new_algo; + newPasswordHash = SRPHelper.getX(newPasswordBytes, algo); + } else { + newPasswordHash = null; + } + } else { + newPasswordBytes = null; + newPasswordHash = null; + } + + RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null && "SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + initPasswordNewAlgo(currentPassword); + setNewPassword(clear); + } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + needHideProgress(); + if (error == null && response instanceof TLRPC.TL_boolTrue) { + if (clear) { + currentPassword = null; + currentPasswordHash = new byte[0]; + loadPasswordInfo(false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didRemovedTwoStepPassword); + updateRows(); + } else { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, newPasswordHash, req.new_settings.new_algo, currentPassword.new_secure_algo, currentPassword.secure_random, email, hint, null, firstPassword); + finishFragment(); + }); + builder.setMessage(LocaleController.getString("YourPasswordSuccessText", R.string.YourPasswordSuccessText)); + builder.setTitle(LocaleController.getString("YourPasswordSuccess", R.string.YourPasswordSuccess)); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); } } - }); + } else if (error != null) { + if ("EMAIL_UNCONFIRMED".equals(error.text)) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + if (closeAfterSet) { + TwoStepVerificationActivity activity = new TwoStepVerificationActivity(currentAccount, 0); + activity.setCloseAfterSet(true); + parentLayout.addFragmentToStack(activity, parentLayout.fragmentsStack.size() - 1); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword, req.new_settings.new_password_hash, req.new_settings.new_algo, currentPassword.new_secure_algo, currentPassword.secure_random, email, hint, email, firstPassword); + finishFragment(); + }); + builder.setMessage(LocaleController.getString("YourEmailAlmostThereText", R.string.YourEmailAlmostThereText)); + builder.setTitle(LocaleController.getString("YourEmailAlmostThere", R.string.YourEmailAlmostThere)); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); + } + } else { + if ("EMAIL_INVALID".equals(error.text)) { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("PasswordEmailInvalid", R.string.PasswordEmailInvalid)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); + } + } + } + }); + + if (!clear) { + if (password != null && currentSecret != null && currentSecret.length == 32) { + if (currentPassword.new_secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 newAlgo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) currentPassword.new_secure_algo; + + byte[] passwordHash = Utilities.computePBKDF2(newPasswordBytes, newAlgo.salt); + byte[] key = new byte[32]; + System.arraycopy(passwordHash, 0, key, 0, 32); + byte[] iv = new byte[16]; + System.arraycopy(passwordHash, 32, iv, 0, 16); + + byte[] encryptedSecret = new byte[32]; + System.arraycopy(currentSecret, 0, encryptedSecret, 0, 32); + Utilities.aesCbcEncryptionByteArraySafe(encryptedSecret, key, iv, 0, encryptedSecret.length, 0, 1); + + req.new_settings.new_secure_settings = new TLRPC.TL_secureSecretSettings(); + req.new_settings.new_secure_settings.secure_algo = newAlgo; + req.new_settings.new_secure_settings.secure_secret = encryptedSecret; + req.new_settings.new_secure_settings.secure_secret_id = currentSecretId; + req.new_settings.flags |= 4; + } + } + + if (currentPassword.new_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + if (password != null) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.new_algo; + req.new_settings.new_password_hash = SRPHelper.getVBytes(newPasswordBytes, algo); + if (req.new_settings.new_password_hash == null) { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "ALGO_INVALID"; + requestDelegate.run(null, error); + } + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error); + } + } else { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + }); } - private void checkSecretValues(byte[] passwordBytes, TLRPC.TL_account_passwordSettings passwordSettings) { - if (passwordSettings.secure_secret.length == 32) { - currentSecret = passwordSettings.secure_secret; - currentSecretSalt = passwordSettings.secure_salt; - currentSecretId = passwordSettings.secure_secret_id; + private TLRPC.TL_inputCheckPasswordSRP getNewSrpPassword() { + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + return SRPHelper.startCheck(currentPasswordHash, currentPassword.srp_id, currentPassword.srp_B, algo); + } + return null; + } - byte[] passwordHash = Utilities.computeSHA512(currentSecretSalt, passwordBytes, currentSecretSalt); + private boolean checkSecretValues(byte[] passwordBytes, TLRPC.TL_account_passwordSettings passwordSettings) { + if (passwordSettings.secure_settings != null) { + currentSecret = passwordSettings.secure_settings.secure_secret; + byte[] passwordHash; + if (passwordSettings.secure_settings.secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) { + TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 algo = (TLRPC.TL_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000) passwordSettings.secure_settings.secure_algo; + passwordHash = Utilities.computePBKDF2(passwordBytes, algo.salt); + } else if (passwordSettings.secure_settings.secure_algo instanceof TLRPC.TL_securePasswordKdfAlgoSHA512) { + TLRPC.TL_securePasswordKdfAlgoSHA512 algo = (TLRPC.TL_securePasswordKdfAlgoSHA512) passwordSettings.secure_settings.secure_algo; + passwordHash = Utilities.computeSHA512(algo.salt, passwordBytes, algo.salt); + } else { + return false; + } + currentSecretId = passwordSettings.secure_settings.secure_secret_id; byte[] key = new byte[32]; System.arraycopy(passwordHash, 0, key, 0, 32); byte[] iv = new byte[16]; System.arraycopy(passwordHash, 32, iv, 0, 16); - Utilities.aesCbcEncryptionByteArraySafe(currentSecret, key, iv, 0, currentSecret.length, 0, 0); + if (!PassportActivity.checkSecret(passwordSettings.secure_settings.secure_secret, passwordSettings.secure_settings.secure_secret_id)) { + TLRPC.TL_account_updatePasswordSettings req = new TLRPC.TL_account_updatePasswordSettings(); + req.password = getNewSrpPassword(); + req.new_settings = new TLRPC.TL_account_passwordInputSettings(); + req.new_settings.new_secure_settings = new TLRPC.TL_secureSecretSettings(); + req.new_settings.new_secure_settings.secure_secret = new byte[0]; + req.new_settings.new_secure_settings.secure_algo = new TLRPC.TL_securePasswordKdfAlgoUnknown(); + req.new_settings.new_secure_settings.secure_secret_id = 0; + req.new_settings.flags |= 4; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }); + currentSecret = null; + currentSecretId = 0; + } } else { currentSecret = null; - currentSecretSalt = null; currentSecretId = 0; } + return true; + } + + private static byte[] getBigIntegerBytes(BigInteger value) { + byte[] bytes = value.toByteArray(); + if (bytes.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(bytes, 1, correctedAuth, 0, 256); + return correctedAuth; + } + return bytes; } private void processDone() { @@ -872,46 +957,80 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific final byte[] oldPasswordBytes = AndroidUtilities.getStringBytes(oldPassword); needShowProgress(); - byte[] hash = new byte[currentPassword.current_salt.length * 2 + oldPasswordBytes.length]; - System.arraycopy(currentPassword.current_salt, 0, hash, 0, currentPassword.current_salt.length); - System.arraycopy(oldPasswordBytes, 0, hash, currentPassword.current_salt.length, oldPasswordBytes.length); - System.arraycopy(currentPassword.current_salt, 0, hash, hash.length - currentPassword.current_salt.length, currentPassword.current_salt.length); - - final TLRPC.TL_account_getPasswordSettings req = new TLRPC.TL_account_getPasswordSettings(); - req.current_password_hash = Utilities.computeSHA256(hash, 0, hash.length); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - needHideProgress(); - if (error == null) { - checkSecretValues(oldPasswordBytes, (TLRPC.TL_account_passwordSettings) response); - currentPasswordHash = req.current_password_hash; - passwordEntered = true; - AndroidUtilities.hideKeyboard(passwordEditText); - updateRows(); - } else { - if (error.text.equals("PASSWORD_HASH_INVALID")) { - onPasscodeError(true); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } - }); + Utilities.globalQueue.postRunnable(() -> { + final TLRPC.TL_account_getPasswordSettings req = new TLRPC.TL_account_getPasswordSettings(); + final byte x_bytes[]; + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + x_bytes = SRPHelper.getX(oldPasswordBytes, algo); + } else { + x_bytes = null; } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + + RequestDelegate requestDelegate = (response, error) -> { + if (error == null) { + Utilities.globalQueue.postRunnable(() -> { + boolean secretOk = checkSecretValues(oldPasswordBytes, (TLRPC.TL_account_passwordSettings) response); + AndroidUtilities.runOnUIThread(() -> { + needHideProgress(); + if (secretOk) { + currentPasswordHash = x_bytes; + passwordEntered = true; + AndroidUtilities.hideKeyboard(passwordEditText); + updateRows(); + } else { + AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); + } + }); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + if ("SRP_ID_INVALID".equals(error.text)) { + TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); + ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { + if (error2 == null) { + currentPassword = (TLRPC.TL_account_password) response2; + initPasswordNewAlgo(currentPassword); + processDone(); + } + }), ConnectionsManager.RequestFlagWithoutLogin); + return; + } + needHideProgress(); + if ("PASSWORD_HASH_INVALID".equals(error.text)) { + onPasscodeError(true); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); + } + }); + } + }; + + if (currentPassword.current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { + TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.current_algo; + req.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, algo); + if (req.password == null) { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "ALGO_INVALID"; + requestDelegate.run(null, error); + return; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + TLRPC.TL_error error = new TLRPC.TL_error(); + error.text = "PASSWORD_HASH_INVALID"; + requestDelegate.run(null, error); + } + }); } } else if (type == 1) { if (passwordSetState == 0) { @@ -965,48 +1084,37 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific } TLRPC.TL_auth_recoverPassword req = new TLRPC.TL_auth_recoverPassword(); req.code = code; - ConnectionsManager.getInstance(currentAccount).sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - if (error == null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword); - finishFragment(); - } - }); - builder.setMessage(LocaleController.getString("PasswordReset", R.string.PasswordReset)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - Dialog dialog = showDialog(builder.create()); - if (dialog != null) { - dialog.setCanceledOnTouchOutside(false); - dialog.setCancelable(false); - } - } else { - if (error.text.startsWith("CODE_INVALID")) { - onPasscodeError(true); - } else if (error.text.startsWith("FLOOD_WAIT")) { - int time = Utilities.parseInt(error.text); - String timeString; - if (time < 60) { - timeString = LocaleController.formatPluralString("Seconds", time); - } else { - timeString = LocaleController.formatPluralString("Minutes", time / 60); - } - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); - } else { - showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); - } - } - } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didSetTwoStepPassword); + finishFragment(); }); + builder.setMessage(LocaleController.getString("PasswordReset", R.string.PasswordReset)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + Dialog dialog = showDialog(builder.create()); + if (dialog != null) { + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(false); + } + } else { + if (error.text.startsWith("CODE_INVALID")) { + onPasscodeError(true); + } else if (error.text.startsWith("FLOOD_WAIT")) { + int time = Utilities.parseInt(error.text); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + } else { + showAlertWithText(LocaleController.getString("AppName", R.string.AppName), error.text); + } } - }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } } } @@ -1092,13 +1200,13 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific privacyCell.setText(""); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else if (position == passwordSetupDetailRow) { - privacyCell.setText(LocaleController.formatString("EmailPasswordConfirmText", R.string.EmailPasswordConfirmText, currentPassword.email_unconfirmed_pattern)); + privacyCell.setText(LocaleController.formatString("EmailPasswordConfirmText", R.string.EmailPasswordConfirmText, currentPassword.email_unconfirmed_pattern != null ? currentPassword.email_unconfirmed_pattern : "")); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); } else if (position == passwordEnabledDetailRow) { privacyCell.setText(LocaleController.getString("EnabledPasswordText", R.string.EnabledPasswordText)); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else if (position == passwordEmailVerifyDetailRow) { - privacyCell.setText(LocaleController.formatString("PendingEmailText", R.string.PendingEmailText, currentPassword.email_unconfirmed_pattern)); + privacyCell.setText(LocaleController.formatString("PendingEmailText", R.string.PendingEmailText, currentPassword.email_unconfirmed_pattern != null ? currentPassword.email_unconfirmed_pattern : "")); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } break; @@ -1118,7 +1226,8 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific public ThemeDescription[] getThemeDescriptions() { return new ThemeDescription[]{ new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{TextSettingsCell.class}, null, null, null, Theme.key_windowBackgroundWhite), - new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundWhite), + new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_windowBackgroundGray), new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault), new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault), diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 49119cdc9..841b03332 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -12,45 +12,45 @@ يرجى التحقق من صحة رمز بلدك وإدخال رقم هاتفك المحمول. اختر دولة رمز الدولة خاطئ - تم تسجيل الدخول إلى هذا الحساب من البرنامج هذا. + تم تسجيل الدخول إلى هذا الحساب من هذا التطبيق. تبديل مزامنة جهات الاتصال - سيؤدي هذا إلى حذف جهات اتصالك من خوادم تيليجرام. إن كان خيار \"مزامنة جهات الاتصال\" مفعلًا، ستتم إعادة مزامنتها. - سيتم إضافة جهات اتصال هذا الجهاز إلى هذا الحساب. + سيؤدي هذا إلى حذف جهات اتصالك من خوادم تيليجرام. إذا كان خيار \"مزامنة جهات الاتصال\" مفعلًا فستتم إعادة مزامنتها تلقائيًا. + ستتم إضافة جهات اتصال هذا الجهاز إلى هذا الحساب. لن يتم إضافة جهات اتصال هذا الجهاز إلى هذا الحساب. - سيتم إضافة جهات اتصال جهازك إلى حسابك. + ستتم إضافة جهات اتصال جهازك هذا إلى حسابك. قم بالتفعيل لمزامنة جهات اتصال هذا الجهاز مع حسابك باستمرار. - تم إضافة جهات اتصال جهازك إلى حسابك. + تمت إضافة جهات اتصال جهازك إلى حسابك. التحقق من الرقم تم إرسال رسالة تحتوي على رمز التفعيل لرقمك **%1$s**. أرسلنا الرمز إلى تطبيق **تيليجرام** على جهازك الآخر. - جارٍ الاتصال على رقمك **%1$s**.\n\nلا داعي للرد، تيليجرام سيقوم بعملية التفعيل تلقائيًا. - جارٍ الاتصال برقمك **%1$s** لإملاء الرمز عليك. + يتم الاتصال على رقمك **%1$s**.\n\nلا حاجة للرد، سيقوم تيليجرام بعملية التفعيل تلقائيًا. + يتم الاتصال برقمك **%1$s** لإملاء الرمز عليك صوتيًا. سيتصل بك تيليجرام خلال %1$d:%2$02d سنقوم بإرسال رسالة قصيرة خلال %1$d:%2$02d - جارٍ الاتصال بك... + يتم الاتصال بك... الرمز - الرقم خاطئ؟ + الرقم غير صحيح؟ لم يصلك الرمز؟ إلغاء إعادة تعيين الحساب - شخص ما لديه صلاحية الوصول لهاتفك **%1$s** طلب حذف حسابك وتعطيل التحقق من حسابك بخطوتين.\n\nإن لم يكن أنت، فضلًا قم بإدخال الرمز الذي أرسلناه للتو برسالة قصيرة. + شخص ما لديه صلاحية الوصول لرقمك **%1$s** طلب حذف حسابك وتعطيل التحقق بخطوتين من حسابك.\n\nإن لم يكن أنت، فقم رجاء بإدخال الرمز الذي أرسلناه للتوِّ برسالة قصيرة. إعادة تعيين الحساب بما أن الحساب **%1$s** فعّال ومحمي بكلمة مرور، سنقوم بحذفه خلال أسبوع لأسباب أمنية.\n\nيمكنك إلغاء هذه العملية في أي وقت. ستتمكن من إعادة تعيين حسابك خلال: تم إلغاء محاولاتك السابقة لإعادة تعيين هذا الحساب. فضلًا أعد المحاولة بعد 7 أيام. إعادة تعيين - رابط غير صحيح أو منتهي. - تم إلغاء عملية حذف حسابك %1$s؟ يمكنك إغلاق هذه النافذة الآن. + رابط غير صحيح أو منتهي الصلاحية. + تم إلغاء عملية حذف حسابك %1$s. يمكنك الآن إغلاق هذه النافذة. اسمك اختر الاسم الأول واسم العائلة - الاسم الأول + الاسم الأول (مطلوب) اسم العائلة (اختياري) إلغاء التسجيل - لقد نجحت في تحويل %1$s إلى %2$s من أجل %3$s + لقد نجحت في تحويل %1$s إلى %2$s مقابل %3$s لقد نجحت في تحويل %1$s إلى %2$s الدفع طرق الشحن @@ -63,7 +63,7 @@ الولاية الدولة الرمز البريدي - المستقبل + المستلِم الاسم الكامل رقم الهاتف البريد الإلكتروني @@ -73,64 +73,64 @@ بطاقة الدفع رقم البطاقة رمز الأمان (CVV) - MM/YY + سنة/شهر عنوان الدفع الاسم حفظ معلومات الدفع يمكنك حفظ معلومات الدفع لاستخدامها لاحقًا. فضلًا قم *بتفعيل التحقق بخطوتين* لتفعيل هذا الخيار. مراجعة العملية - هل حقًا ترغب في تحويل %1$s إلى البوت %2$s لـ %3$s؟ + هل ترغب حقًا في تحويل %1$s إلى البوت %2$s مقابل %3$s؟ الإجمالي الفاتورة الفاتورة التجريبية - إدفع %1$s + ادفع %1$s وسيلة الدفع - مزود عملية الدفع + موفِّر عملية الدفع الاسم رقم الهاتف عنوان التواصل طريقة الشحن - الفاتورة - اختر بطاقة أخرى + إيصالُ الدفع + اختر بطاقة مختلفة بطاقتك %1$s مسجلة مسبقًا. لتتمكن من استخدامها، يرجى إدخال كلمة مرور التحقق بخطوتين. المعذرة، تم إلغاء عملية الدفع من البوت. المعذرة، تم رفض عملية الدفع. - تعذر الوصور إلى خادم الدفع. فضلًا تحقق من اتصال الانترنت وحاول مرة أخرى. + تعذر الوصور إلى خادم الدفع. تحقق رجاءً من اتصالك بالإنترنت وحاول مرة أخرى. تحذير - لا يمتلك تيليجرام، ولا %1$s صلاحيات الوصول إلى معلومات بطاقتك الإئتمانية. تفاصيل البطاقات الإئتمانية تتم معالجتها مباشرة عن طريق نظام الدفع, %2$s.\n\nالدفعات تذهب لشكل مباشر إلى مطور %1$s. تيليجرام لا يوفر أية ضمانات، لذلك استمر على مسؤوليتك. في حال وجود مشاكل، تواصل مع مطور %1$s أو البنك الخاص بك. - كلمة المرور وamp; البريد الإلكتروني + لا يملك تيليجرام ولا %1$s صلاحياتِ الوصولِ إلى معلومات بطاقتك الإئتمانية. تفاصيل البطاقات الإئتمانية تتم معالجتها مباشرة عن طريق نظام الدفع %2$s.\n\nالدفعات المالية تذهب بشكل مباشر إلى مطور %1$s. لا يوفر تيليجرام أي ضمانات حول عملية الشراء، لذلك استمر على مسئوليتك. في حال وجود مشاكل يمكنك التواصل مع مطور %1$s أو مع المَصرف الخاص بك. + كلمة المرور والبريد الإلكتروني كلمة المرور أدخل كلمة مرور أعد إدخال كلمة المرور يرجى اختيار كلمة مرور لحماية معلومات الدفع الخاصة بك. ستطلب منك عند تسجيل الدخول. بريد الاسترداد بريدك الإلكتروني - فضلًا قم بإضافة بريدًا إلكترونيًا صحيحًا. هذه هي الطريقة الوحيدة لاستعادة كلمة مرور منسية. + فضلًا قم بإضافة بريد إلكتروني صالح، هذه هي الطريقة الوحيدة لاستعادة كلمة المرور المنسية. سيتم إرسال الرقم إلى %1$s كمعلومات الدفع. سيتم إرسال البريد الإلكتروني إلى %1$s كمعلومات الدفع. - سيتم إرسال الرقم والبريد الإلكتروني إلى %1$s كمعلومات الدفع. + سيتم إرسال رقم الهاتف والبريد الإلكتروني إلى %1$s كمعلومات دفع. محادثات جديدة الإعدادات جهات الاتصال مجموعة جديدة - أمس + يوم أمس لا توجد نتائج - ...لا توجد محادثات بعد + لا توجد محادثات بعد... المستعرضة مؤخرًا إخفاء - ابدأ المراسلة بالضغط على\nأيقونة النقاط في أعلى يمين الشاشة\nأو اذهب لقسم جهات الاتصال. - ابدأ المراسلة عبر الضغط\nعلى زر الرسالة في الزاوية السفلية\nأو اضغط على زر القائمة للمزيد من الخيارات. + ابدأ المراسلة عبر الضغط على\nزر الرسالة في الزاوية السفلية للشاشة\nأو اضغط على زر القائمة للمزيد من الخيارات. + ابدأ المراسلة عبر الضغط على\nزر الرسالة في الزاوية السفلية الشاشة\nأو اضغط على زر القائمة للمزيد من الخيارات. في انتظار الشبكة... جارٍ الاتصال... متصل التماس: %1$d م.ث جارٍ التحقق... - متوفر - غير متوفر + متاح + غير متاح جارٍ الاتصال بالبروكسي - وصل البروكسي + الاتصال بالبروكسي جارٍ التحديث... محادثة سرية جديدة بانتظار %s ليتصل بالإنترنت... @@ -139,7 +139,7 @@ انضم %s لمحادثتك السرية. لقد انضممت للمحادثة السرية مسح سجل المحادثة - حذف من الذاكرة المخبئية + حذف من الذاكرة المؤقتة حذف وخروج حذف المحادثة حساب محذوف @@ -148,24 +148,24 @@ صورة سرية مقطع مرئي سري صورة متحركة سرية - %1$s يستخدم إصدار قديم من تيليجرام، لذلك، الصور السرية ستظهر في وضع الموافقة.\n\nعندما يقوم %2$s بتحديث تيليجرام، الصور التي بها عداد دقيقة أو أقل ستعمل بطريقة \"الاستمرار بالضغط للإستعراض\"، وسيتم إخبارك عندما يلتقط المستقبل صورة من شاشته. + يستخدم %1$s إصدارًا قديمًا من تيليجرام، لذلك ستظهر الصور السرية في الوضع التوافقي.\n\nعندما يقوم %2$s بتحديث تيليجرام فإن الصور التي بها عداد تدمير خلال دقيقة أو أقل ستعمل بطريقة \"الاستمرار بالضغط للمشاهدة\"، وسيتم إخبارك عندما يلتقط المستقبل صورة للشاشة. الرسائل بحث كتم الإشعارات - ضعه على الصامت لمدة %1$s + كتم لمدة %1$s إلغاء الكتم خلال %1$s تعطيل - الأوسمة + الوُسُوم الأخيرة المحادثات حذف %1$s من الاقتراحات؟ معاينة الرابط مسودة تم مسح السجل - من %1$s - %1$s من %2$s - اكتب رأيك بخصوص هذا الإستعراض + بواسطة %1$s + %1$s بواسطة %2$s + اكتب رأيك حول هذا الإستعراض إرسال الملصق عرض الحزمة تثبيت في الأعلى @@ -174,65 +174,65 @@ وضع علامة مقروء غامق مائل - رمز + ترميز عادي - يحتاج **تيليجرام** إلى الوصول لجهات اتصالك لكي تستطيع التواصل مع أصدقائك عبر جميع أجهزتك. ستتم مزامنة جهات اتصالك باستمرار مع خوادم تيليجرام السحابية المشفرة بشدة. + يحتاج **تيليجرام** إلى الوصول لجهات اتصالك لكي تتمكن من التواصل مع أصدقائك عبر جميع أجهزتك، ستتم مزامنة جهات اتصالك باستمرار مع خوادم تيليجرام السحابية شديدة التشفير. ليس الآن الاستمرار جهات اتصالك في تيليجرام ترقية إلى مشرف - لا يوجد مستخدمين محظورين + لا يوجد مستخدمون محظورون حذف المجموعة مغادرة المجموعة حذف المجموعة - ستخسر كافة الرسائل في هذه المجموعة. + ستَفقد كافة الرسائل في هذه المجموعة. يمكنك إضافة مشرفين لمساعدتك في إدارة المجموعة. اضغط عليهم مطولًا لحذفهم. - لحظة! حذف هذه المجموعة سيزيل كافة الأعضاء والرسائل سيتم حذفها. هل أنت متأكد من رغبتك في حذف المجموعة؟ + انتظر! حذف هذه المجموعة سيزيل ويحذفُ كافة الأعضاء والرسائل، هل أنت متأكد من رغبتك في حذف المجموعة؟ تم إنشاء مجموعة un1 أضافك لهذه المجموعة - هل أنت متأكد أنك تريد مغادرة المجموعة؟ + هل أنت متأكد من رغبتك في مغادرة المجموعة؟ المعذرة، لا يمكنك إضافة هذا المستخدم للمجموعات. المعذرة، المجموعة ممتلئة. - المعذرة, هذا المستخدم قرر مغادرة المجموعة, لا يمكنك دعوته مرة أخرى للمجموعة. + المعذرة، قرر هذا المستخدم مغادرة المجموعة، لا يمكنك دعوته مرة أخرى إليها. المعذرة، يوجد الكثير من المشرفين في هذه المجموعة. المعذرة، يوجد الكثير من حسابات البوت في هذه المجموعة. un1 ثبت \"%1$s\" un1 ثبت رسالة un1 ثبت صورة - un1 ثبت مقطع مرئي - un1 ثبت ملفًا + ثبت un1 مقطعًا مرئيًا + ثبت un1 ملفًا un1 ثبت ملصقًا - un1 ثبت رسالة صوتية - un1 ثبت رسالة مرئية + ثبت un1 رسالةً صوتيةً + ثبت un1 رسالةً مرئيةً un1 ثبت جهة اتصال un1 ثبت %1$s un1 ثبت خريطةً - un1 ثبت موقعًا حيًا + ثبت un1 موقعًا حيًا un1 ثبت صورة متحركة - un1 ثبت مقطع صوتي + ثبت un1 مقطعًا صوتيًا تمّت ترقية هذه المجموعة إلى مجموعة خارقة - تم ترقية المجموعة %1$s لمجموعة خارقة - أعضاء القائمة السوداء هم أعضاء تم إزالتهم من المجموعة ويمكنهم فقط العودة إليها بدعوة من مشرف ما. روابط الدعوة لن تعمل لهم. - أعضاء القائمة السوداء هم أعضاء تم حذفهم من القناة ولا يمكنهم العودة لها إلا بدعوة من المشرف. روابط الدعوة لن تمكنهم من العودة للقناة. + تمت ترقية %1$s إلى مجموعة خارقة + الأعضاء المحظورون هم أعضاء تمت إزالتهم من المجموعة، ولا يمكنهم العودة إليها إلا بدعوة من مشرف ما، روابط الدعوة لن تفيدهم. + في حال حَظرِ العضو من القناة فإنه تتم إزالته منها، ولا يمكنه العودة إليها إلا بدعوة من المشرف، ولن يتمكن من الدخول عبر الروابط الخاصة. قناة جديدة اسم القناة إضافة جهات اتصالك لقناتك يستطيع الناس مشاركة هذا الرابط مع غيرهم ويمكنهم إيجاد قناتك من خلال البحث في تيليجرام. يستطيع الناس مشاركة هذا الرابط مع غيرهم ويمكنهم إيجاد مجموعتك من خلال البحث في تيليجرام. الرابط - يستطيع الناس الدخول إلى قناتك عبر الرابط فقط. يمكنك تعطيل الرابط في أي وقت. - يستطيع الناس الانضمام لمجموعتك من خلال هذا الرابط. يمكنك تعطيله في أي وقت. + يستطيع الناس الانضمام لقناتك من خلال هذا الرابط. يمكنك استبداله في أي وقت. + يستطيع الناس الانضمام لمجموعتك من خلال هذا الرابط. يمكنك استبداله في أي وقت. الوصف (اختياري) الوصف يمكنك إضافة وصف اختياري لقناتك. قناة عامة مجموعة عامة يمكن إيجاد القنوات العامة من خلال البحث ويستطيع أي شخص الانضمام لها. - يمكن إيجاد المجموعات العامة من خلال البحث، سجل المحادثة متاح للجميع ويستطيع أي شخص الانضمام. + يمكن العثور على المجموعات العامة من خلال البحث، سجل المحادثة متاح للجميع، ويمكن لأي شخص الانضمام إليها. قناة خاصة مجموعة خاصة - يمكن الانضمام للقنوات الخاصة فقط عن طريق رابط دعوة. + يمكن الانضمام للقنوات الخاصة عن طريق رابط الدعوة فقط. يمكن الانضمام للمجموعات الخاصة فقط في حال تمت دعوتك أو بواسطة رابط دعوة. الرابط رابط الدعوة @@ -241,20 +241,20 @@ مغادرة القناة الإعدادات انضمام - منشور + المنشور منشور صامت ما هي القنوات؟ - القنوات هي أداة جديدة لإيصال رسائلك لجمهور عريض. - أنشاء قناة - عذرًا، هذا الاسم مأخوذ. + القنوات هي أداة جديدة لإيصال رسائلك لجمهور واسع وغير محدود. + إنشاء قناة + عذرًا، هذا الاسم محجوز. المعذرة، الاسم غير مقبول. - اسم القناة يجب أن يتكوّن من 5 حروف على الأقل. - الاسم يجب ألا يتخطى ٣٢ حرف كحد أقصى. + يجب أن تتكون روابط القنوات من 5 خانات على الأقل. + لا يمكن أن يتخطى الاسم 32 حرفًا كحد أقصى. أسماء القنوات لا يمكن أن تبدأ برقم. أسماء المجموعات يجب أن تتكوّن من 5 حروف على الأقل. أسماء المجموعات لا يمكن أن تبدأ برقم. جارٍ التحقق من الاسم... - %1$s متوفر. + %1$s متاح. أعضاء "المشتركون " المحظورون @@ -263,68 +263,68 @@ المشرفون حذف القناة حذف القناة - مهلًا! حذف هذه القناة سيزيل كافة أعضائها وسيحذف رسائلها. هل أنت متأكد من رغبتك في حذفها؟ + مهلًا! حذف هذه القناة سيزيل كافة أعضائها ويَحذف جميعَ رسائلها، هل أنت متأكد من رغبتك في حذفها؟ هل أنت متأكد من رغبتك في مغادرة القناة؟ - ستخسر كافة الرسائل في هذه القناة. + ستَفقد كافة المنشورات في هذه القناة. تعديل - فضلًا اختر رابط لقناتك العامة ليتمكن الناس من إيجادها من خلال البحث ومشاركتها مع غيرهم.\n\nإلى لم ترغب بذلك، يفضّل إنشاء قناة خاصة بدلًا من العامة. + فضلًا قم باختيار رابط لقناتك العامة ليتمكن الناس من إيجادها عبر البحث ومشاركتِها مع غيرهم.\n\nإذا لم ترغب بذلك، ننصحك بإنشاء قناة خاصة بدلا منها. تم إنشاء القناة تم تغيير صورة القناة - تم إزالة صورة القناة + تمت إزالة صورة القناة تم تغيير اسم القناة إلى un2 - المعذرة، لقد قمت بحجز أسماء مستخدمين كثيرة. يمكنك إلغاء بعض روابط مجموعاتك وقنواتك القديمة, أو قم بجعلها خاصة. + المعذرة، لقد قمت بحجز أسماء مستخدمين كثيرة. يمكنك تعطيل بعض روابط مجموعاتك وقنواتك القديمة, أو قم بإنشاء واحدة خاصة عوضًا عن ذلك. المُنشئ كتم إلغاء الكتم إضافة مشرف حظر مستخدم إلغاء الحظر - اضغط باستمرار على المستخدم لإلغاء الحظر - دعوة من خلال رابط + اضغط باستمرار على المستخدم لرفع الحظر عنه + الدعوة عبر رابط خاص إزالة المشرف يمكن لمشرفي القناة فقط مشاهدة هذه القائمة. - سيستطيع أي شخص يملك تيليجرام على جهازه الانضمام لقناتك عبر هذا الرابط. - يمكنك إضافة مشرفين لمساعدتك في إدارة المجموعة. اضغط عليهم مطولًا لحذفهم. + يمكن لمستخدمي تيليجرام الانضمام إلى قناتك عبر هذا الرابط. + يمكنك إضافة مشرفين لمساعدتك في إدارة المجموعة، اضغط مطوَّلا على أيٍّ منهم لحذفه. هل ترغب في الانضمام لقناة \'%1$s\'؟ - المعذرة، هذه المحادثة لم تعد متاحة. - للأسف، تم حظرك عن المشاركة في المجموعات العامة. - المعذرة، هذه المحادثة لم تعد متاحة. + المعذرة، لم تعد هذه المحادثة متاحة. + للأسف، تم حظرك من المشاركة في المجموعات العامة. + المعذرة، لم تعد هذه المحادثة متاحة. هل ترغب بإضافة %1$s للقناة؟ - المعذرة، هذا المستخدم قرر مغادرة القناة, لا يمكنك دعوته مرة أخرى للقناة. + المعذرة، قرر هذا المستخدم مغادرة القناة، لا يمكنك دعوته مرة أخرى إليها. المعذرة، لا يمكنك إضافة هذا المستخدم للقنوات. المعذرة، يوجد الكثير من المشرفين في هذه القناة. المعذرة، يوجد الكثير من حسابات البوت في هذه القناة. - المعذرة، يمكنك إضافة أول ٢٠٠ عضو للقناة فقط. يمكن لعدد غير محدود من الأعضاء الدخول للقناة عن طريق رابط القناة. + المعذرة، يمكنك إضافة أول 200 عضو للقناة فقط. يمكن لعدد غير محدود من الناس الانضمامُ للقناة عبرَ رابطها. un1 أضافك لهذه القناة - لقد انضممت لهذه القناة - لقد انضممت لهذه المجموعة - إزالة من القناة + انضممتَ إلى القناة + قمتَ بالانضمام لهذه المجموعة + الإزالة من القناة المعذرة، لا يمكنك إرسال رسائل لهذه القناة. "%1$s أضافك لقناة %2$s " - تم تحديث صورة القناة %1$s + تم تحديث صورة قناة %1$s %1$s نشر رسالة %1$s نشر صورة - %1$s نشر مقطع مرئي + نشر %1$s مقطعًا مرئيًا %1$s نشر جهة اتصال %1$s نشر موقعًا %1$s نشر موقعًا حيًا %1$s نشر ملفًا %1$s نشر صورة متحركة %1$s نشر %2$s - %1$s نشر رسالة صوتية - %1$s نشر رسالة مرئية - %1$s نشر مقطع صوتي - %1$s نشر ملصق - %1$s نشر ملصق %2$s + نشر %1$s رسالةً صوتيةً + نشر %1$s رسالةً مرئيةً + نشر %1$s مقطعًا صوتيًا + نشر %1$s ملصقًا + نشر %1$s ملصق %2$s من يستطيع إضافة أعضاء؟ جميع الأعضاء المشرفون فقط - سيتم إشعار الأعضاء عندما تنشر - لن يتم إشعار الأعضاء عندما تنشر + سيتم إشعار الأعضاء بالمنشورات الجديدة + لن يتم إشعار الأعضاء بالمنشورات الجديدة توقيع الرسائل إضافة أسماء المشرفين للرسائل التي يرسلونها. التعديل على صلاحيات المشرف - ماذا يمكن لهذا المشرف فعله؟ + ما هي صلاحيات هذا المشرف؟ تغيير معلومات القناة تغيير معلومات المجموعة نشر الرسائل @@ -337,12 +337,12 @@ إضافة مستخدمين دعوة مستخدمين من خلال الرابط تثبيت رسائل - تمت الإضافة بواسطة %1$s + قام %1$s بإضافته لا يمكنك تعديل حقوق هذا المشرف. - مُقيد من قبل %1$s + مُقيّد من قِبل %1$s قيود المستخدم قراءة الرسائل - ماذا يمكن لهذا المستخدم فعله؟ + ما هي صلاحيات هذا المستخدم؟ إرسال الرسائل إرسال الوسائط إرسال الملصقات والصور المتحركة @@ -366,11 +366,11 @@ كافة المشرفين **لا توجد أحداث هنا بعد**\n\nأعضاء المجموعة ومشرفيها\nلم يقوموا بأي أحداث\nخلال الـ 48 ساعة الماضية. **لا توجد أحداث هنا بعد**\n\nمشرفي القناة\nلم يقوموا بأي أحداث\nخلال الـ 48 ساعة الماضية. - **لم يتم العثور على أحداث**\n\nلا توجد أحداث تطابق ما قمت بالبحث\nعنه حصلت مؤخرًا. + **لم يتم العثور على أحداث**\n\nلا توجد نتائج تطابق ما بحثت عنه\nضمن الأحداث الأخيرة. لا توجد أحداث حصلت مؤخرًأ تحوي \'**%1$s**\' تم العثور عليها. ما هي آخر الأحداث؟ - هي قائمة تحوي جميع الأحداث التي قام بها أعضاء المجموعة ومشرفوها خلال الـ 48 ساعة الماضية. - هذه قائمة بجميع الأحداث التي قام بها أعضاء القناة ومشرفوها خلال الـ 48 ساعة الماضية. + هي قائمة تحوي جميع الأحداث التي قام بها أعضاء المجموعة ومشرفوها خلال آخِر 48 ساعة. + هي قائمة تحوي جميع الأحداث التي قام بها مشرفو القناة خلال آخِر 48 ساعة. un1 غيّر اسم المجموعة إلى \"%1$s\" un1 غيّر اسم القناة إلى \"%1$s\" un1 غادر المجموعة @@ -382,8 +382,8 @@ un1 انضم للقناة un1 عيّن صورة جديدة للمجموعة un1 عيّن صورة جديدة للقناة - un1 أزال صورة المجموعة - un1 أزال صورة القناة + أزال un1 صورة المجموعة + أزال un1 صورة القناة un1 عدل هذه الرسالة: un1 عدل الوصف: عدّل un1 ملف الوسائط: @@ -393,7 +393,7 @@ فارغ un1 ثبت هذه رسالة: un1 ألغى تثبيت رسالة - un1 حذف هذه رسالة: + حذف un1 هذه الرسالة: un1 غير حزمة ملصقات المجموعة \nun1 أزال حزمة ملصقات المجموعة un1 غير رابط المجموعة: @@ -404,12 +404,12 @@ un1 عدل وصف المجموعة: un1 عدل وصف القناة: الوصف السابق - un1 جعل سجل المحادثة في المجموعة ظاهر للأعضاء الجدد - un1 أخفى سجل المحادثة عن أعضاء المجموعة الجدد + جعل un1 سجل المحادثة في المجموعة ظاهرًا للأعضاء الجدد + جعل un1 سجل محادثة المجموعة مخفيًا للأعضاء الجدد un1 فعّل دعوات المجموعة un1 عطّل دعوات المجموعة - un1 فعّل التواقيع - un1 عطّل التواقيع + فعّل un1 التواقيع + عطّل un1 التواقيع غير القيود الخاصة بـ %1$s\n\nلمدة: %2$s إرسال الملصقات والصور المتحركة إرسال الوسائط @@ -417,7 +417,7 @@ تضمين روابط قراءة الرسائل غير صلاحيات %1$s - غير معلومات القناة + تغيير معلومات القناة تغيير معلومات المجموعة نشر الرسائل تعديل الرسائل @@ -439,14 +439,14 @@ رسالة جماعية جديدة أدخل اسم القائمة - أنت قمت بإنشاء قائمة رسالة جماعية + أنشأتَ قائمة للرسالة الجماعية إضافة مستلم إزالة من قائمة الرسالة الجماعية - فضلًا قم بإضافة ملفات لمكتبتك الموسيقية على جهازك لتتمكن من مشاهدتها هنا. - موسيقى - فنان غير معروف - العنوان غير معروف + فضلًا قم بإضافة ملفات لمكتبتك الصوتية على جهازك لتتمكن من مشاهدتها هنا. + مقطع صوتي + المؤدي غير معروف + عنوان غير معروف عشوائي ترتيب عكسي @@ -454,7 +454,7 @@ متاح %1$s من %2$s حدث خطأ غير معروف خطأ في الوصول - حجم الملف لا يمكن أن يكون أكبر من %1$s + لا يمكن أن يتجاوز حجم الملف %1$s الذاكرة غير موجودة نقل USB مفعل الذاكرة الداخلية @@ -479,24 +479,24 @@ "يكتبون… " %1$s يكتب... %1$s يكتبون... - %1$s يقوم بتسجيل رسالة صوتية... - %1$s يقوم بتسجيل رسالة مرئية... + يسجل %1$s رسالةً صوتيةً... + يسجل %1$s رسالةً مرئيةً... %1$s يقوم بإرسال مقطع صوتي... %1$s يرسل صورة استعراض فوري افتح المجموعة افتح القناة عرض الرسالة - سيتم تفعيل النمط الداكن تلقائيًا في الليل + سيتم تفعيل النمط المظلم في الليل تلقائيًا %1$s يلعب لعبة... %1$s يقوم بإرسال مقطع مرئي... يرسل %1$s ملفًا... - يسجل رسالة صوتية... - يسجل رسالة مرئية... - يرسل ملف صوتي... + يسجل رسالةً صوتيةً... + يسجل رسالةً مرئيةً... + يرسل ملفًا صوتيًا... يرسل صورة... يلعب لعبة... - يرسل مقطع مرئي... + يرسل مقطعًا مرئيًا... يرسل ملفًا... هل يوجد لديك سؤال\nحول تيليجرام؟ المعرض @@ -505,7 +505,7 @@ ملف الكاميرا ما من رسائل هنا بعد... - الرسالة المعاد توجيهها + تمت إعادة التوجيه من من %1$s من: @@ -517,9 +517,9 @@ %s دعاك للانضمام لمحادثة سرية. لقد قمت بدعوة %s لمحادثة سرية. المحادثات السرية: - استخدم التشفير من البداية للنهاية + تستخدم التشفير من البداية للنهاية لا تترك أثرًا في خوادمنا - تمتلك عداد للتدمير الذاتي + تملك عدادًا للتدمير الذاتي لا تسمح بتحويل الرسائل تمت إزالتك من هذه المجموعة لقد قمت بمغادرة المجموعة @@ -529,7 +529,7 @@ حفظ في الجهاز حفظ في الصور المتحركة هل ترغب بحذف الصورة المتحركة؟ - حفظ في الموسيقى + حفظ في الجهاز مشاركة تطبيق ملف التعريب تطبيق النمط من الملف @@ -538,14 +538,14 @@ إشعارات الخدمة جارٍ جلب معلومات الرابط... فتح بواسطة... - افتح باستخدام... + فتح باستخدام... إرسال %1$s رفع %1$s - إرسال كملف - إرسال كملفات - هل ترغب في فتح الرابط باستخدام %1$s ؟ + إرسال دون ضغط + إرسال دون ضغط + هل ترغب في فتح الرابط %1$s؟ إلغاء الإرسال - هل ترغب في السماح لـ %1$s بإرسال هويتك على تيليجرام (ليس رقم هاتفك) واسمك للصفحات التي تفتحها من خلال هذا البوت؟ + هل ترغب في السماح لـ %1$s بإرسال اسمك ورقم هويتك على تيليجرام (ليس رقم هاتفك) إلى الصفحات التي تفتحها من خلال هذا البوت؟ تبليغ عن إزعاج تبليغ عن إزعاج ومغادرة إضافة جهة اتصال @@ -554,10 +554,10 @@ هل أنت متأكد من رغبتك في التبليغ عن إزعاج من هذه المجموعة؟ هل أنت متأكد من رغبتك في التبليغ عن إزعاج من هذه القناة؟ المعذرة، فقط يمكنك مراسلة جهات الاتصال المشتركة في الوقت الحالي. - المعذرة، فقط يمكنك إضافة جهات الاتصال المشتركة للمجموعات في الوقت الحالي. + المعذرة، يمكنك فقط إضافة جهات الاتصال المشتركة للمجموعات في الوقت الحالي. معلومات أكثر إرسال إلى... - اكتب ملاحظة + اكتب تعليقًا... اضغط هنا للوصول للصور المتحركة المحفوظة تثبيت إشعار جميع الأعضاء @@ -568,7 +568,7 @@ حظر المستخدم إبلاغ عن إزعاج مسح الكل من %1$s - مسح الإيموجيات الأخيرة؟ + مسح الرموز التعبيرية الأخيرة؟ تبليغ تم إرسال البلاغ إزعاج @@ -581,26 +581,26 @@ تعديل الرسالة تعديل الوصف انقر لتعديل الوسائط - انتقل إلى الأسفل للبوتات + مرِّر إلى الأسفل للبوتات %1$s - المعذرة، انتهت مدة التعديل على الرسائل. + المعذرة، انتهت مهلة التعديل على الرسائل. إضافة اختصار - بحث الأعضاء + البحث عن أعضاء أعد التوجيه إلى هنا للحفظ الرسائل المحفوظة أعد التوجيه إلى هنا للحفظ. أنت أعد توجيه الرسائل إلى هنا لحفظها - أرسل الوسائط والملفات لحفظهم - افتح هذه المحادثة من أي جهاز من أجهزتك + أرسل الوسائط والملفات لحفظها + افتح هذه المحادثة عبر أي جهاز من أجهزتك استخدم البحث لتجد الأشياء بسرعة مساحتك السحابية اذهب لهذا التاريخ - حذف لـ%1$s - حذف لكافة الأعضاء + حذف من عند %1$s + حذف من عند كافة الأعضاء تم نسخ النص للحافظة - اضغط باستمرار لتسجيل صوتي. انقر للتحويل للمرئي. - اضغط باستمرار لتسجيل مرئي. انقر للتحويل للصوتي. + اضغط مطولًا لتسجيل الصوت، انقر للتحويل للمرئي. + اضغط مطولًا لتسجيل مرئي، انقر للتحويل للصوتي. تجاهل الرسالة الصوتية هل أنت متأكد من رغبتك في إيقاف التسجيل وتجاهل الرسالة الصوتية؟ تجاهل الرسالة المرئية @@ -615,7 +615,7 @@ مشرفو هذه المجموعة قيدوك من إرسال الملصقات إليها مشرفو هذه المجموعة قيدوك من الكتابة فيها مشرف - "تثبيت ملفات APK محظور لهذا التطبيق. يمكنك تفعيل هذا في إعدادات النظام. " + "تثبيت ملفات APK محظور لهذا التطبيق، يمكنك السماح بهذا من إعدادات النظام. " الرسائل غير المقروءة بحث عن حزم الملصقات الرابط @@ -624,7 +624,7 @@ تيليجرام جوجل ياندكس - Nobody + لا أحد %1$s عيّن عداد التدمير الذاتي ليصبح %2$s قمت بتعيين عداد التدمير الذاتي ليصبح %1$s @@ -632,44 +632,44 @@ لقد عطلتَ عداد التدمير الذاتي لديك رسالة جديدة %1$s: %2$s - %1$s أرسل لك %2$s - %1$s أعاد تحويل %2$s لك - %1$s ارسل لك رسالة - %1$s أرسل لك صورة - %1$s أرسل مقطع مرئي - %1$s أرسل لك فاتورة %2$s - %1$s أرسل لك صورة بتدمير ذاتي - %1$s أرسل لك مقطع مرئي بتدمير ذاتي + أرسل لك %1$s %2$s + أعاد %1$s تحويل %2$s إليك + أرسل لك %1$s رسالةً + أرسل لك %1$s صورةً + أرسل لك %1$s مقطعًا مرئيًا + أرسل لك %1$s فاتورة %2$s + أرسل لك %1$s صورةً ذاتية التدمير + أرسل لك %1$s مقطعًا مرئيًا ذاتي التدمير %1$s شارك جهة اتصال معك - %1$s أرسل لك موقعًا - %1$s أرسل لك موقعًا حيًا + أرسل لك %1$s موقعًا + أرسل لك %1$s موقعًا حيًا %1$s دعاك للعب %2$s - %1$s أرسل لك ملفًا - %1$s أرسل صورة متحركة - %1$s ارسل لك رسالة صوتية - %1$s أرسل رسالة مرئية لك - %1$s أرسل مقطع صوتي - %1$s أرسل لك ملصقًا - %1$s ارسل لك ملصق %2$s + " أرسل لك %1$s ملفًا" + أرسل لك %1$s صورةً متحركةً + أرسل لك %1$s رسالةً صوتيةً + أرسل لك %1$s رسالةً مرئيةً + أرسل لك %1$s مسارًا + أرسل لك %1$s ملصقًا + أرسل لك %1$s ملصق %2$s %1$s @ %2$s: %3$s %1$s أرسل رسالة للمجموعة %2$s - %1$s أرسل صورة للمجموعة %2$s - %1$s أرسل مقطع مرئي للمجموعة %2$s + أرسل %1$s صورةً لمجموعة %2$s + أرسل %1$s مقطعًا مرئيًا لمجموعة %2$s %1$s شارك جهة اتصال مع المجموعة %2$s %1$s أرسل موقعًا حيًا للمجموعة %2$s %1$s أرسل موقعًا حي إلى المجموعة %2$s %1$s دعا المجموعة %2$s للعب %3$s - %1$s أرسل ملفًا للمجموعة %2$s - %1$s أرسل صورة متحركة للمجموعة %2$s + أرسل %1$s ملفًا لمجموعة %2$s + أرسل %1$s صورةً متحركةً لمجموعة %2$s %1$s أرسل فاتورة إلى المجموعة %2$s لقاء %3$s - %1$s أرسل رسالة صوتية للمجموعة %2$s - %1$s أرسل رسالة مرئية للمجموعة %2$s - %1$s أرسل مقطع صوتي للمجموعة %2$s - %1$s أرسل ملصق للمجموعة %2$s - %1$s أرسل ملصق %3$s للمجموعة %2$s + أرسل %1$s رسالةً صوتيةً لمجموعة %2$s + أرسل %1$s رسالةً مرئيةً لمجموعة %2$s + أرسل %1$s مقطعًا صوتيًا لمجموعة %2$s + أرسل %1$s ملصقًا لمجموعة %2$s + أرسل %1$s ملصق %3$s لمجموعة %2$s %1$s أضافك إلى المجموعة %2$s %1$s انضم للمجموعة %2$s - %1$s غير صورة المجموعة %2$s + غيّر %1$s صورة المجموعة %2$s %1$s أضاف %3$s للمجموعة %2$s %1$s عاد إلى المجموعة %2$s %1$s انضم للمجموعة %2$s @@ -677,7 +677,7 @@ %1$s أزالك من المجموعة %2$s %1$s غادر المجموعة %2$s انضم %1$s لتيليجرام! - %1$s,\nتم تسجيل الدخول لحسابك من جهاز جديد عند %2$s\n\nالجهاز: %3$s\nالموقع: %4$s\n\nإن لم تكن أنت من قام بتسجيل الدخول، يمكنك الذهاب للإعدادات - الخصوصية والأمان - الجلسات النشطة - إنهاء الجلسة.\n\nإن كنت تعتقد أن شخصًا ما قام بتسجيل الدخول دون رغبتك, يمكنك تفعيل التحقق بخطوتين في قسم الخصوصية واﻷمان في الإعدادات.\n\nشكرًا,\nفريق تيليجرام + %1$s، \nلقد تم تسجيل الدخول لحسابك هذا من جهاز جديد في: %2$s\n\nالجهاز: %3$s\nالموقع: %4$s\n\nإن لم تكن أنت من قام بتسجيل الدخول فيمكنك الذهاب للإعدادات - الخصوصية والأمان - الجلسات النشطة - ومن ثم إنهاء الجلسات المريبة.\n\nإذا كنت تعتقد أن شخصًا ما قام بتسجيل الدخول دون إذنك فيمكنك تفعيل التحقق بخطوتين من خلال قسم الخصوصية واﻷمان في الإعدادات.\n\nشكرًا، \nفريق تيليجرام %1$s حدث صورته الشخصية %1$s انضم للمجموعة %2$s عبر رابط دعوة %1$s أرسل %3$s إلى المجموعة %2$s @@ -691,34 +691,34 @@ %1$s ثبت رسالة في المجموعة %2$s %1$s ثبت صورة في المجموعة %2$s %1$s ثبت لعبة في المجموعة %2$s - %1$s ثبت مقطع مرئي في المجموعة %2$s - %1$s ثبت ملف في المجموعة %2$s - %1$s ثبت ملصق في المجموعة %2$s - %1$s ثبت ملصق %3$s في المجموعة %2$s - %1$s ثبت رسالة صوتية في المجموعة %2$s - %1$s ثبت رسالة مرئية في المجموعة %2$s + ثبت %1$s مقطعًا مرئيًا في المجموعة %2$s + ثبت %1$s ملفًا في المجموعة %2$s + ثبت %1$s ملصقًا في مجموعة %2$s + ثبت %1$s ملصق %3$s في مجموعة %2$s + ثبت %1$s رسالةً صوتيةً في مجموعة %2$s + ثبت %1$s رسالةً مرئيةً في مجموعة %2$s %1$s ثبت جهة اتصال في المجموعة %2$s %1$s ثبت خريطة في المجموعة %2$s - %1$s ثبت موقع حي في المجموعة %2$s + ثبت %1$s موقعًا حيًا في مجموعة %2$s %1$s ثبت صورة متحركة في المجموعة %2$s - %1$s ثبت مقطع صوتي في المجموعة %2$s - %1$s ثبت فاتورة في المجموعة %2$s + ثبت %1$s مقطعًا صوتيًا في المجموعة %2$s + ثبت %1$s فاتورةً في مجموعة %2$s %1$s ثبت \"%2$s\" %1$s ثبت رسالة %1$s ثبت صورة %1$s ثبت لعبة - %1$s ثبت مقطع مرئي - %1$s ثبت ملف + ثبت %1$s مقطعًا مرئيًا + ثبت %1$s ملفًا %1$s ثبت فاتورة %1$s ثبت ملصق - %1$s ثبت ملصق %2$s - %1$s ثبت رسالة صوتية - %1$s ثبت رسالة مرئية + ثبت %1$s ملصق %2$s + ثبت %1$s رسالةً صوتيةً + ثبت %1$s رسالةً مرئيةً %1$s ثبت جهة اتصال %1$s ثبت خريطة - %1$s ثبت موقع حي + ثبت %1$s موقعًا حيًا %1$s ثبت صورة متحركة - %1$s ثبت مقطع صوتي + ثبت %1$s مقطعًا صوتيًا تيليجرام اختر جهة اتصال @@ -726,9 +726,9 @@ لا توجد جهات اتصال بعد مرحبا، أنا استخدم تيليجرام للمحادثة. انضم إلينا! قم بتنزيله من هنا: %1$s في - أمس عند + يوم أمس عند الساعة %1$s - أمس عند %1$s + يوم أمس عند %1$s متصل آخر ظهور آخر ظهور @@ -740,13 +740,13 @@ آخر ظهور كان قريبًا آخر ظهور خلال أسبوع آخر ظهور خلال شهر - آخر ظهور خلال فترة طويلة + آخر ظهور كان منذ زمن طويل رسالة جديدة - اختر جهات الاتصال لدعوتهم لتيليجرام + اختر جهات اتصال لدعوتها إلى تيليجرام دعوة إلى تيليجرام شارك تيليجرام... هل ترغب في تحديث جهات الاتصال؟ - قام تيليجرام باكتشاف العديد من جهات الاتصال غير المُتزامنة، هل ترغب في مزامنتها الآن؟ اختر \"نعم\" إن كنت تستخدم جهازك الخاص، شريحتك، وحساب جوجل الخاص بك. + اكتشف تيليجرام العديد من جهات الاتصال غير المزامَنة، هل ترغب في مزامنتها الآن؟ اختر \"نعم\" إن كنت تستخدم جهازك الخاص، شريحتك، وحساب جوجل الخاص بك. إضافة أشخاص... ستتمكن من إضافة أعضاء أكثر إذا انتهيت من إنشاء المجموعة وقمت بتحويلها إلى مجموعة خارقة. @@ -761,23 +761,23 @@ تم نسخ البريد للحافظة قم بالدعوة للمجموعة عبر رابط رابط الدعوة - هل أنت متأكد من رغبتك في تعطيل الرابط؟ إن قمت بذلك، لن يستطيع أحد الانضمام عبره. - رابط الدعوة السابق لم يعد يعمل. تم توليد رابط جديد. - تعطيل - تعطيل الرابط + هل أنت متأكد من رغبتك في استبدال الرابط؟ إن قمت بذلك، لن يستطيع أحد الانضمام عبره. + رابط الدعوة السابق لم يعد مفعلًا، تم إنشاء رابط جديد بدلًا منه. + استبدال + استبدال الرابط هل أنت متأكد من رغبتك في تعطيل الرابط **%1$s**؟\n\nستصبح المجموعة \"**%2$s**\" خاصة. هل أنت متأكد من رغبتك في تعطيل الرابط **%1$s**؟\nستصبح القناة \"**%2$s**\" خاصة. نسخ الرابط مشاركة الرابط - سيستطيع أي شخص يملك تيليجرام على جهازه الانضمام لمجموعتك عبر هذا الرابط. + يمكن لمستخدمي تيليجرام الانضمام إلى مجموعتك عبر هذا الرابط. مشرفو المحادثة - جميع الأعضاء مشرفين + جميع الأعضاء مشرفون يستطيع جميع الأعضاء إضافة أعضاء جدد، تعديل اسم وصورة المجموعة. يستطيع المشرفون فقط إضافة وإزالة الأعضاء، تعديل اسم وصورة المجموعة. أعضاء - الوسائط المشاركة + الوسائط المتبادَلة الإعدادات "إضافة مشترك " إضافة عضو @@ -791,10 +791,10 @@ تحويل إلى مجموعة خارقة تحويل إلى مجموعة خارقة تحذير - هذا القرار لا يمكن الرجوع عنه. لن تتمكن من إرجاع المجموعات الخارقة لتصبح مجموعات عادية. - **تم بلوغ الحد الأقصى لعدد الأعضاء**\n\nلتخطي هذا الحد والحصول على خصائص جديدة، يمكنك الترقية لمجموعة خارقة:\n\n• يمكن للمجموعات الخارقة إحتواء %1$s عضو\n• يمكن للأعضاء الجدد مشاهدة سجل المحادثة كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين تثبيت الرسائل المهمة\n• يمكن لمُنشئ المجموعة إنشاء رابط عام لها - ** في المجموعات الخارقة:**\n\n• يمكن للأعضاء الجدد مشاهدة سجل المحادثة كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين تثبيت الرسائل المهمة\n• يمكن لمُنشئ المجموعة إنشاء رابط عام لها - **ملاحظة:** لن يكون بإمكانك الرجوع عن هذا القرار. + تحذير: هذا القرار لا يمكن التراجع عنه، لن تتمكن من إعادة المجموعة الخارقة إلى مجموع عادية مرة أخرى. + **تم بلوغ الحد الأقصى لعدد الأعضاء**\n\nلتخطي هذا الحد والحصول على خصائص جديدة، يمكنك الترقية لمجموعة خارقة:\n\n• يمكن أن تحتوي المجموعات الخارقة على %1$s عضو\n• يمكن للأعضاء الجدد مشاهدة سجل المحادثات كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين تثبيت الرسائل المهمة\n• يمكن لمُنشئ المجموعة إنشاء رابط عام لها + ** في المجموعات الخارقة:**\n\n• يمكن للأعضاء الجدد مشاهدة سجل المحادثات كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين تثبيت الرسائل المهمة\n• يمكن لمُنشئ المجموعة إنشاء رابط عام لها + **ملحوظة:** لن يكون بإمكانك التراجع عن هذا القرار. مشاركة إضافة @@ -809,7 +809,7 @@ العمل آخر الرئيسية - مهنة + المهنة الميلاد اللقب إنشاء جهة اتصال جديدة @@ -821,75 +821,75 @@ المجموعات المشتركة المجموعات المشتركة لا توجد مجموعات مشتركة بعد - حدث خطأ. + حدث خطأ ما. مفتاح التشفير عداد التدمير الذاتي - إن عينت عدادًا، ستتدمر الصورة تلقائيًا بعد مشاهدتها. - إن عينت عدادًا، سيتدمر المقطع المرئي تلقائيًا بعد مشاهدته. + إن قمت بتعيين العداد فسيتم تدمير الصورة تلقائيًا بعد مشاهدتها. + إن قمت بتعيين العداد فسيتم تدمير المقطع المرئي تلقائيًا بعد مشاهدته. إيقاف تم اشتقاق الصورة والنص من مفتاح تشفير هذه المحادثة السرية مع **%1$s**.\n\nإن كانت مطابقة لما يظهر على جهاز **%2$s**، فالتشفير من البداية للنهاية مضمون.\n\nللاستزادة، اطلع على telegram.org - https://telegram.org/faq#secret-chats + https://telegram.org/faq/ar#g غير معروف معلومات هاتف اسم المستخدم اسم المستخدم الخاص بك - عذرًا، هذا الاسم مأخوذ. + عذرًا، هذا الاسم محجوز. المعذرة، اسم المستخدم غير مقبول. يجب ألا يقل اسم المستخدم عن 5 حروف. - اسم المستخدم يجب ألا يتخطى ٣٢ حرف كحد أقصى. + لا يمكن أن يتخطى الاسم 32 حرفًا كحد أقصى. عذرًا، لا يمكن لاسم المستخدم بأن يبدأ برقم. - يمكنك اختيار اسم مستخدم في **تيليجرام**. إن قمت بذلك، سيتمكن الأشخاص الآخرون من العثور عليك عن طريق اسم المستخدم هذا والتواصل معك دون معرفة رقم هاتفك.\n\nتستطيع استخدام **حروف اللغة الإنجليزية**, **وأرقامها** وكذلك الشرطة السفلية. الطول الأدنى هو **خمسة** أحرف. + يمكنك اختيار اسم مستخدم لحسابك في **تيليجرام**، إذا قمت بذلك سيتمكن المستخدمون الآخرون من العثور عليك والتواصل معك عبر هذا الاسم دون معرفة رقمك.\n\nيمكنك استخدام **الحروف والأرقام الإنجليزية** وكذلك الشَّرطة السفلية. الطول الأدنى هو **خمسُ خانات**. يقوم هذا الرابط بفتح محادثة معك في تيليجرام:\n%1$s - جارٍ مراجعة اسم المستخدم... - %1$s متوفر. + جارٍ التحقق من اسم المستخدم... + %1$s متاح. لا شيء - حدث خطأ. + حدث خطأ ما. الملصقات إضافة ملصق إضافة أقنعة إضافة إلى الملصقات إضافة للمفضلة - تم إضافة الملصق للمفضلة + تمت إضافة الملصق للمفضلة تم إزالة الملصق من المفضلة مستخدمة حديثًا المفضلة ملصقات المجموعة احذف من المفضلة إضافة إلى الأقنعة - لا يوجد ملصقات - تم إزالة الملصقات - الأقنعة المُزالة - تم إضافة ملصقات جديدة - تم إضافة أقنعة جديدة + لم يُعثر على الملصقات + تمت إزالة الملصقات + تم حذف الأقنعة + تمت إضافة ملصقات جديدة + تمت إضافة أقنعة جديدة أرشفة مشاركة نسخ الرابط إزالة لا يوجد ملصقات بعد لم يتم العثور على ملصقات - لا يوجد أقنعة بعد + لا توجد أقنعة بعد الأقنعة - يمكنك إضافة أقنعة للصور التي ترسلها. لعمل ذلك، قم بفتح محرر الصور قبل إرسال الصورة. + يمكنك إضافة أقنعة للصور التي ترسلها، لعمل ذلك قم بفتح محرر الصور قبل إرسال الصورة. الملصقات الشائعة - اقتراح ملصقات عبر الإيموجي + اقتراح ملصقات عبر الرموز الكل المُضافة إيقاف - هذه الملصقات منتشرة الآن على تيليجرام. يمكنك إضافة ملصقات مخصصة من خلال بوت @stickers . + هذه الملصقات شائعة حاليًا على تيليجرام. يمكنك إضافة ملصقات مخصصة من خلال البوت @stickers. الملصقات المؤرشفة الأقنعة المؤرشفة - لا توجد ملصقات مؤرشفة - لا توجد أقنعة مؤرشفة + ما من ملصقات مؤرشفة + ما من أقنعة مؤرشفة يمكنك الاحتفاظ بـ 200 حزمة ملصقات كحدٍ أقصى. ستتم أرشفة الحزم غير المستخدمة عند إضافتك للمزيد. يمكنك الاحتفاظ بـ 200 حزمة أقنعة كحدٍ أقصى. ستتم أرشفة الحزم غير المستخدمة عند إضافتك للمزيد. إرسال الملصق الملصقات المؤرشفة تمت أرشفة بعض من حزم الملصقات الخاصة بك. يمكنك تفعيل هذه الحزم ان طريق إعدادات الملصقات. الأقنعة المؤرشفة - تمت أرشفة بعض من حزم الأقنعة الخاصة بك. يمكنك تفعيل هذه الحزم ان طريق إعدادات الأقنعة. + تمت أرشفة بعض من حزم الأقنعة الخاصة بك. يمكنك إعادة تفعيل هذه الحزم عن طريق إعدادات الأقنعة. النمط الوضع الليلي الآلي @@ -897,15 +897,15 @@ مجدول تلقائي الجدولة - استخدام مواقيت الشروق والغروب المحلية + استخدام التوقيت المحلي للشروق والغروب تحديث الموقع يتطلب حساب مواعيد الشروق والغروب التحقق لمرة واحدة من موقعك التقريبي. يرجى العلم أن موقعك يتم حفظه في جهازك فقط.\n\nالغروب: %1$s\nالشروق: %2$s من حتى النمط الليلي المفضل مؤشر السطوع - قم بالتحويل للنمط الليلي عند انخفاض السطوع تحت %1$d%%. - داكن + قم بالتبديل للنمط الليلي عند انخفاض الإضاءة المحيطة إلى %1$d%% أو أقل. + مظلم أزرق هل أنت متأكد من رغبتك في حذف النمط؟ ملف النمط غير صحيح @@ -915,18 +915,18 @@ نمط جديد تطبيق معاينة النمط - اختر لون + اختر لونًا إنشاء نمط جديد - اضغط على أيقونة الألوان لاستعراض قائمة الخيارات في كل شاشة - ثم قم بتعديلهم. - يمكنك إنشاء النمط الخاص بك لتغيير الألوان داخل التطبيق. يمكنك دائمًا العودة لنمط تيليجرام الأصلي من هنا. + اضغط على أيقونة الألوان لاستعراض قائمة الخيارات في كل شاشة - ثم قم بتعديلها. + يمكنك إنشاء نمطك الخاص لتغيير الألوان داخل التطبيق. يمكنك العودةُ دائمًا لنمط تيليجرام الافتراضي من هنا. - تم تعيين كافة الإشعارات افتراضيا - هل أنت متأكد من رغبتك في إعادة تعيين إعدادات الإشعارات؟ + تم تعيين كل الإشعارات إلى الوضع الافتراضي + هل أنت متأكد من رغبتك في إعادة تعيين إعدادات الإشعارات إلى الوضع الافتراضي؟ حجم خط الرسائل اسأل سؤالًا تفعيل المؤثرات البصرية إلغاء الحظر - اضغط باستمرار على المستخدم لإلغاء الحظر + اضغط باستمرار على المستخدم لرفع الحظر عنه لا يوجد مستخدمون محظورون بعد إشعارات الرسائل التنبيه @@ -934,7 +934,7 @@ إشعارات المجموعات الصوت إشعارات داخل التطبيق - الأصوات داخل التطبيق + أصوات داخل التطبيق اهتزازات داخل التطبيق الاهتزاز معاينة داخل التطبيق @@ -944,7 +944,7 @@ الإشعارات والأصوات الإشعارات المخصصة الإشعارات المنبثقة - الرسائل الجديدة من هذا المستخدم ستظهر على شاشتك حتى عند عدم استخدامك لتيليجرام. + ستظهر الرسائل الجديدة من هذا المستخدم على الشاشة حتى لو كنت خارج تطبيق تيليجرام. LED اللون أزرق @@ -953,24 +953,26 @@ أخضر سماوي أبيض - بني داكن - داكن + بني + مظلم زهري - حجم النص + مقاس الخط بنفسجي برتقالي - الـ LED هي إضاءة صغيرة تومض في بعض الأجهزة كإشعار برسالة جديدة. - الإشعارات الأكثر أهمية ستعمل حتى عندما يكون جهازك في وضعية عدم الإزعاج. + الـ LED هو إضاءة صغيرة تومض في بعض الأجهزة كإشعار مرئي بالرسائل الجديدة. + ستعمل الإشعارات الأكثر أهمية حتى في حال تفعيل وضعية عدم الإزعاج. عام + مكتومة + مُلغى كتمها تشغيل إيقاف - Default (On) - Default (Off) + الافتراضي (مفعل) + الافتراضي (معطّل) تشغيل إيقاف المستخدمون المحظورون تسجيل الخروج - لا يوجد صوت + بدون صوت افتراضي الدعم فقط في وضع الصامت @@ -982,7 +984,7 @@ الرسائل المثبتة اللغة مخصص - نرجو الأخذ بالعلم أن الدعم الفني في تيليجرام يقوم به مجموعة من المتطوعين. نحاول الرد بسرعة قدر المستطاع، لكن من الممكن أن نستغرق بعض الوقت.\n\nيرجى الإطلاع على \nصفحة الأسئلة الشائعة عن تيليجرام\n]]>: يوجد بها إجابات لمعظم الأسئلة و حلول للعديد من المشاكل.]]> + نرجو الأخذ بالعلم أن الدعم الفني في تيليجرام يقوم به مجموعة من المتطوعين. نحاول الرد سريعًا قدر الإمكان، لكن ذلك قد يستغرق بعض الوقت.\n\nيرجى الإطلاع على الأسئلة الشائعة عن تيليجرام]]> فهي تحوي إجابات لمعظم الأسئلة وحلولًا للعديد من المشاكل.]]> اسأل متطوعًا الأسئلة الشائعة الأسئلة الشائعة @@ -992,11 +994,11 @@ سياسة الخصوصية شروط الخدمة من خلال تسجيلك،\nأنت توافق على *شروط الخدمة*. - https://telegram.org/privacy + https://telegram.org/faq/ar#a10 حذف التعريب؟ ملف التعريب غير صحيح - خدمة التشغيل المستمر - إعادة تشغيل التطبيق في حال تم إقفاله من المستخدم أو النظام. هذا سيساعد في إظهار التطبيق للإشعارات. + التشغيل المستمر في الخلفية + إعادة تشغيل التطبيق في الخلفية إذا قام المستخدم أو النظام بإيقافه. سيضمن هذا إظهارَ التطبيق للإشعارات. الاتصال في الخلفية استخدام اتصال طفيف في الخلفية للتأكد من وصول إشعارات تيليجرام. قم بالتفعيل لإشعارات أقوى. فرز حسب @@ -1006,10 +1008,10 @@ لون إضاءة الـ LED الإشعارات المنبثقة بدون إشعارات منبثقة - فقط عندما تكون الشاشة تعمل - فقط عندما تكون الشاشة مطفأة + في حال تشغيل الشاشة فقط + في حال إغلاق الشاشة فقط أظهرها دائمًا - عداد الشارات + شارةُ عدّاد الرسائل قصير طويل تنزيل الوسائط تلقائيًا @@ -1019,14 +1021,14 @@ عند استخدام البيانات الخلوية عند الاتصال بالـ Wi-Fi عند تواجدك خارج البلاد - لا يوجد وسائط + لا وسائط تشغيل الصور المتحركة تلقائيًا الرفع للتحدث حفظ في المعرض تعديل الاسم تخصيص مخصص - تفعيل الإشعارات مخصصة + تفعيل الإشعارات المخصصة الأهمية كما في الإعدادات منخفضة @@ -1035,13 +1037,13 @@ مهمة جدًا مطلقًا إعادة الإشعارات - يمكنك تغيير رقم تيليجرام الخاص بك هنا. سيتم نقل حسابك وجميع بياناتك التي في سحابة تيليجرام بما فيها رسائلك، الوسائط، جهات الاتصال وغيرها للرقم الجديد.\n\n**هام:** ستحصل جميع جهات اتصالك على **رقمك الجديد**، في حال تواجد رقمك القديم عندهم ولم تقم بحظرهم في تيليجرام. - ستحصل جميع جهات اتصالك على رقمك الجديد، في حال تواجد رقمك القديم عندهم ولم تقم بحظرهم في تيليجرام. + يمكنك تغيير رقم تيليجرام الخاص بك هنا، سيتم نقل حسابك وجميع بياناتك التي في سحابة تيليجرام بما فيها رسائلك، الوسائط، جهات الاتصال وغيرها للرقم الجديد.\n\n**هام:** ستحصل جميع جهات اتصالك على **رقمك الجديد**، في حال وجود رقمك القديم عندها وعدم قيامك بحظرها سابقًا في تيليجرام. + ستحصل جميع جهات اتصالك على رقمك الجديد، في حال وجود رقمك القديم عندها وعدم قيامك بحظرها سابقًا في تيليجرام. تغيير الرقم الرقم الجديد سيتم إرسال رسالة SMS قصيرة تحوي رمز التفعيل إلى رقمك الجديد. - الرقم %1$s لديه حساب تيليجرام مسبقًا. يرجى حذف هذا الحساب قبل محاولة تغيير رقمك. - آخر + الرقم %1$s مرتبط بالفعل بحساب آخَر على تيليجرام. يرجى حذف ذلك الحساب قبل محاولة تغيير رقمك. + غير ذلك تعطيل مفعلة معطّلة @@ -1051,9 +1053,12 @@ افتراضي افتراضي إشعارات ذكية + الاستثناءات + "يحوي هذا القسم على جميع المحادثات التي تملك إعدادات إشعارات مخصصة.\n\nيمكنك تخصيص إشعارات المحادثات عبر فتح صفحاتها واختيار \'الإشعارات\'. " + لا شيء %1$d / %2$s تعطيل - تردد صوت التنبيه + تكرار صوت التنبيه %1$s خلال %2$s معاينة الروابط يتم توليد معاينات الروابط على خوادم تيليجرام. لا نقوم بتخزين المعلومات حول الروابط التي ترسلها. @@ -1062,9 +1067,9 @@ فتح الروابط الخارجية داخل التطبيق مشاركة مباشرة اظهار المحادثات الأخيرة في قائمة المشاركة - إيموجي - رسم إيموجي واحد كبير - استخدم نظام الإيموجي الافتراضي + الرموز التعبيرية + رسمُ رمز تعبيري واحد كبير + استخدم الرموز التعبيرية الافتراضية تيليجرام للأندرويد %1$s قائمة المعالجة إرسال السجلات @@ -1074,11 +1079,11 @@ استيراد جهات الاتصال إعادة تنزيل جهات الاتصال إعادة تعيين الحوارات - تفعيل الكاميرا داخل التطبيق - عطل الكاميرا داخل التطبيق + تفعيل الكاميرا الداخلية للتطبيق + تعطيل الكاميرا الداخلية للتطبيق إعادة ضبط جهات الاتصال المستوردة - حذف الذاكرة المخبئية للملفات المُرسلة. - يمكنك تغيير اللغة الخاصة بك من الإعدادات لاحقًا. + حذف الوسائط المرسَلة من الذاكرة المؤقتة + يمكنك تغيير لغة التطبيق لاحقًا من الإعدادات. اختر لغتك أخرى إعدادات البروكسي @@ -1104,8 +1109,8 @@ استخدام البروكسي للمكالمات قد تقلل خوادم البروكسي من جودة مكالماتك. تفعيل - ملاحظة - مساحة تخزين جهازك تقريبًا ممتلئة. لإيجاد مساحة إضافية، يمكنك جعل تيليجرام القيام بتنزيل الوسائط الحديثة فقط. + ملحوظة + مساحة جهازك ممتلئة تقريبًا، لتحرير مساحة إضافية يمكنك جعل تيليجرام يقوم بالتخزين المؤقت للوسائط الحديثة فقط. احذف الوسائط بعد عدم الإزالة جهات الاتصال @@ -1115,25 +1120,26 @@ تقييد بالحجم حتى %1$s البث - بث الموسيقى والمقاطع المرئية - لا يمكن بث بعض المقاطع المرئية – مثال: جميع المقاطع المرئية التي تم إرسالها من تيليجرام نسخة 4.7 أو قبل. + بَثُّ الصوتيات والمقاطع المرئية + بعض المقاطع المرئية لا يمكن بثها – على سبيل المثال: كل المقاطع المرئية التي تم إرسالها من نسخة التطبيق 4.7 أو ما قبلها. + انقر لتغيير رقم الهاتف قاعدة البيانات على الجهاز - هل ترغب في مسح الرسائل المحفوظة في الذاكرة المخبئية؟ + هل ترغب في مسح الرسائل النصية من الذاكرة المؤقتة؟ مسح قاعدة البيانات على الجهاز سيحذف الرسائل التي تم تنزيلها على جهازك ويقوم بضغط قاعدة البيانات لتوفير مساحة على جهازك. تيليجرام يحتاج لبعض البيانات ليعمل، لذلك حجم قاعدة البيانات لن يصل إلى صفر.\n\nهذه العملية ربما تأخذ عدة دقائق لتتم. - مسح الذاكرة المخبئية + مسح الذاكرة المؤقتة مسح جارٍ الحساب... المستندات الصور - رسالة صوتية/مرئية + الرسائل الصوتية/المرئية المقاطع المرئية - الموسيقى + الصوتيات الصور المتحركة الملفات الأخرى إفراغ الإحتفاظ بالوسائط - سيتم حذف الصور، المقاطع المرئية وجميع الملفات المحفوظة في خوادمنا التي **لم تستخدمها** خلال هذه المدة لتوفير المساحة على هذا الجهاز.\n\nستبقى ملفات الوسائط في خوادم تيليجرام وبوسعك إعادة تنزيلها متى ما احتجتها مرة أخرى. + سيتم حذف جميع الصور، المقاطع المرئية، وجميع الملفات المحفوظة في خوادمنا والتي **لم تقم باستخدامها** خلال هذه المدة لتوفير المساحة على هذا الجهاز.\n\nمع ذلك ستبقى جميع الملفات في خوادم تيليجرام، ويمكنك إعادة تنزيلها مرة أخرى متى ما احتجتها. للأبد الرسائل الصوتية الرسائل المرئية @@ -1142,23 +1148,35 @@ المعلومات المطلوبة المعلومات المضافة ماهو جواز تيليجرام؟ - مع **جواز تيليجرام** تستطيع التسجيل في المواقع والخدمات التي تتطلب توثيق الهوية الشخصية بسهولة.\n\nمعلوماتك، بياناتك الشخصية ووثائقك محمية ومشفرة من البداية للنهاية. لا أحد، بما فيهم تيليجرام، يستطيع الوصول إليهم دون موافقتك. \n\nيمكنك زيارة الأسئلة الشائعة للإستزادة. - يرجى إنشاء كلمة مرور لحماية بياناتك الشخصية باستخدام تشفير من البداية للنهاية.\n\nستكون كلمة المرور هذه مطلوبة أيضًا عند تسجيل دخولك إلى تيليجرام على جهاز جديد. + مع **جواز تيليجرام** يمْكنك التسجيل في المواقع والخدمات التي تتطلب توثيق الهوية الشخصية بسهولة.\n\nمعلوماتك، بياناتك الشخصية ووثائقك محمية ومشفرة من البداية للنهاية. لا أحد بما فيهم تيليجرام ذاتُه يمكنه الوصول إليها دون إذنك. \n\nلمزيد من التفاصيل يمكنك زيارة الأسئلة الشائعة عن تيليجرام. + يرجى إنشاء كلمة مرور لحماية بياناتك الشخصية باستخدام التشفير من البداية للنهاية.\n\nستكون كلمة المرور هذه مطلوبة أيضًا عند تسجيل دخولك إلى تيليجرام على جهاز جديد. إنشاء كلمة مرور - حذف الجواز - هل أنت متأكد أنك تريد حذف جوازك التيليجرام؟ + حذف جواز تيليجرام + هل أنت متأكد من رغبتك في حذف جواز تيليجرام الخاص بك؟ يرجى استخدام الأحرف اللاتينية فقط - قم برفع نسخة عن فاتورتك الخدمية. - قم برفع نسخة عن كشف رصيدك البنكي. - قم برفع نسخة عن عقدك الإجار. + قم برفع نسخ ترجمة موثّقة عن جواز سفرك. + قم برفع نسخ ترجمة موثّقة عن جوازك الداخلي. + قم برفع نسخ ترجمة موثّقة عن رخصتك القيادة. + قم برفع نسخ ترجمة موثّقة عن بطاقة هويتك الشخصية. + قم برفع نسخة من فاتورتك الخدمية. + قم برفع نسخة من كشف حسابك المصرفي. + قم برفع نسخة من عقد الإيجار الخاص بك. + قم برفع نسخة من صفحة تسجيل جوازك + رفع نسخة من تسجيلك المؤقت. لتأكيد عنوانك, يرجى رفع نسخة من الوثائق التالية (جميع الصفحات). + قم برفع نسخ ترجمة موثّقة عن فاتورتك الخدمية. + قم برفع نسخ ترجمة موثّقة عن كشف حسابك المصرفي. + قم برفع نسخ ترجمة موثّقة عن عقد الإيجار الخاص بك. + قم برفع نسخ ترجمة موثّقة عن صفحة تسجيل جوازك. + "قم برفع نسخ ترجمة موثّقة عن تسجيلك المؤقت. " + قم برفع نسخ ترجمة موثّقة عن الوثيقة المحددة. إضافة فاتورة خدمية - إضافة كشف رصيد بنكي + إضافة كشفِ حساب مصرفي إضافة عقد إيجار العنوان عنوان السكن يرجى إضافة عنوانك - رفع دليل على عنوانك + رفع دليل لإثبات عنوان السكن العنوان الشارع الشارع @@ -1173,98 +1191,160 @@ استخدام نفس الرقم المُستخدم في تيليجرام. استخدام البريد المُستخدم في تيليجرام. أو أدخل رقم هاتف جديد - "تنويه: سيصلك رمز التأكيد إلى رقم الهاتف الذي تقوم بتزويده. " + تنويه: سيصلك رمز التأكيد عبر رقم الهاتف المختارِ أعلاه. البريد حذف البريد الإلكتروني؟ أدخل بريدك الإلكتروني - "تنويه: سيصلك رمز التأكيد إلى البريد الإلكتروني الذي قمت بإضافته. " - الكود - قم بإدخال رقم الكود الذي أرسلناه إلى %1$s + "تنويه: سيصلك رمز التأكيد عبر البريد الإلكتروني الذي أضفتَه. " + الرمز + قم بإدخال رمز التفعيل الذي أرسلناه إلى %1$s يرجى إدخال كلمة مرورك للوصول إلى بياناتك الشخصية. - يطلب %1$s الوصول إلى بياناتك الشخصية لتسجيلك في خدماتهم. - يرجى إدخال كلمة مرورك في تيليجرام لفك تشفيير بياناتك + يطلب **%1$s** الوصول لبياناتك الشخصية لتسجيلك في خدماتهم. + يرجى إدخال كلمة مرورك في تيليجرام لفك تشفير بياناتك أنت توافق على سياسة خصوصية %1$s وتسمح لـ@%2$s بمراسلتك. - أنتة تقوم بإرسال وثائقك إلى %1$s مباشرةً وتقوم بالسماح لـ@%2$s بمراسلتك. - سماح + أنت ترسل وثائقك إلى %1$s مباشرةً وتسمح لـ@%2$s بمراسلتك. + السماح إضافة جواز إضافة جواز داخلي تسجيل الجواز - رفع نسخة عن صفحة تسجيل جوازك. تسجيل مؤقت - رفع نسخة عن تسجيلك المؤقت. إضافة بطاقة هوية شخصية إضافة رخصة قيادة - التفاصيل الشخصية - قم بإدخال تفاصيلك الشخصية + المعلومات الشخصية + قم بتعبئة معلوماتك الشخصية وثيقة الهوية - رفع نسخة عن جوازك أو أي هوية شخصية - التفاصيل الشخصية + قم برفع نسخة من جوازك أو أي هوية شخصية + Upload a scan of your passport + Upload a scan of your internal passport + Upload a scan of your identity card + Upload a scan of your driver\'s license + المعلومات الشخصية + تفاصيل الوثيقة الاسم - اختر الجنس + الاسم الأوسط + اسم العائلة + الاسم (بالأحرف اللاتينية) + الاسم الأوسط (بالأحرف اللاتينية) + اسم العائلة (بالأحرف اللاتينية) + الاسم (%1$s) + الاسم الأوسط (%1$s) + اسم العائلة (%1$s) + تحديد الجنس ذكر أنثى - الكنية تاريخ الميلاد الجنس - رقم الوثيقة - ينتهي + رقم جواز السفر + انتهاء الصلاحية الجنسية الإقامة صورة ذاتية الوثائق المطلوبة - قم برفع صورة ذاتية لك حاملًا الوثيقة + قم برفع صورة ذاتية لك بينما تقوم بحمل الوثيقة + الترجمة الوجه الأمامي - رفع نسخة عن الوجه الأمامي للوثيقة هذه - الوجه المعاكس - رفع نسخة عن الوجه المعاكس للوثيقة - الصفحة الرئيسية - رفع صورة عن الصفحة الرئيسية للوثيقة + رفع صورة عن الوجه الأمامي لهذه الوثيقة + الوجه الخلفي + رفع صورة عن الوجه الخلفي لهذه الوثيقة + الصفحة الرئيسية للجواز + رفع صورة عن الصفحة الرئيسية لجواز السفر تحديد تاريخ انتهاء الصلاحية لا تنتهي صلاحيتها بلا تحديد تاريخ الولادة حذف الصورة الذاتية؟ - يجب أن تحتوي الوثيقة على صورتك، اسمك الأول واسم عائلتك، تاريخ الميلاد، رقم المستند، بلد الإصدار، وتاريخ انتهاء الصلاحية. + يجب أن تحتوي الوثيقة على الصورة الشخصية، الاسم الأول والعائلي، تاريخ الميلاد، رقم المستند، بلد الإصدار، وتاريخ انتهاء الصلاحية. هل أنت متأكد من رغبتك في تجاهل كافة المعلومات التي أدخلتها؟ تجاهل النسخ حذف الوثيقة حذف - هل أنت متأكد أنك تريد حذف هذه النسخة؟ + هل أنت متأكد من رغبتك في حذف هذه النسخة؟ هل أنت متأكد أنك تريد حذف هذه الصورة الذاتية؟ - هل أنت متأكد أنك تريد حذف هذه الوثيقة؟ - هل أنت متأكد أنك تريد حذف تفاصيلك الشخصية؟ + هل أنت متأكد من رغبتك في حذف هذه الوثيقة؟ + هل أنت متأكد من رغبتك في حذف معلوماتك الشخصية؟ هل أنت متأكد من رغبتك في حذف معلومات العنوان؟ - حذف التفاصيل الشخصية + حذف المعلومات الشخصية حذف معلومات العنوان حذف النسخة؟ رفع النسخ - رفع نسخة إضافية + رفع نسخ إضافية لا يمكنك رفع أكثر من %1$s ملف. يمكنك رفع الصور فقط. تصوير جوازك قم بتصوير منطقة القراءة الآلية من جوازك أو بطاقة هويتك الشخصية لتعبئة بياناتك الشخصية تلقائيًا. إضافة وثيقة - لا تملك أية وثائق حتى الآن - يمكنك إضافة رقم هاتفك، بريدك الإلكتروني، وثيقة الهوية أو عنوان السكن. + لا تملك أيَّ وثائقَ حتى الآن + يمكنك إضافة رقم هاتفك، بريدك الإلكتروني، وثيقة الهوية الشخصية، أو عنوان السكن. انقر لتصحيح الأخطاء. + %1$s أو %2$s + اسمك + اسمك في %1$s + اسمك في لغة الدولة التي أصدرت الوثيقة (%1$s). + يرجى التأكد إن كان هذا الاسم صحيحًا:\n\n%1$s %2$s %3$s + العربية + الأذرية + البلغارية + البنغالية + التشيكية + الدانماركية + الألمانية + المالديفية + الدزونكية + الإغريقية + الإسبانية + الأستونية + الفارسية + الفرنسية + العبرية + الكرواتية + الهنغارية + الأرمنية + الأندونيسية + الأيسلندية + الإيطالية + اليابانية + الجورجية + الخميرية + الكورية + اللاوية + اللتوانية + اللاتفية + المقدونية + المنغولية + الملاوية + البورمية + النبالية + الهولندية + البولندية + البرتغالية + الرومانية + الروسية + السلوفاكية + السلوفينية + التايلندية + التركمانية + التركية + الأوكرانية + الأوزبكية + الفيتنامية الجلسات النشطة الجلسة الحالية - لا توجد جلسات نشطة أخرى - يمكنك تسجيل الدخول لحسابك في تيليجرام من جوال، جهاز لوحي، أو جهاز كمبيوتر آخر باستخدام نفس رقم الهاتف. سيقوم تيليجرام بمزامنة كافة بياناتك بشكل لحظي. + ما من جلسات أخرى نشطة حاليًا + يمكنك تسجيل الدخول لحسابك في تيليجرام عبر جوال، جهاز لوحي، أو جهاز حاسوب آخر باستخدام رقم الهاتف ذاته. سيقوم تيليجرام بمزامنة كافة بياناتك بشكل فوري. الجلسات النشطة تحكم بجلساتك على الأجهزة الأخرى. - اضغط على جلسة لإنهائها. + لإنهاء جلسة ما قم بالضغط عليها. إنهاء هذه الجلسة؟ لتسجيل الخروج من جميع الأجهزة عدا هذا الجهاز - هل أنت متأكد من إنهاء جميع الجلسات النشطة الأخرى؟ + هل أنت متأكد من رغبتك في إنهاء جميع الجلسات النشطة الأخرى؟ إنهاء جميع الجلسات الأخرى تطبيق غير رسمي - ما من عمليات تسجيل دخول نشطة + ما من دخولٍ مسجَّل نشط حاليًا يمكنك تسجيل الدخول عبر تيليجرام إلى المواقع التي تدعم ذلك. المواقع المتصلة - المسجل الدخول إليها عبر تيليجرام + تم تسجيل الدخول إليها عبر تيليجرام اضغط لفك الارتباط مع حسابك في تيليجرام. فك الارتباط مع %1$s؟ حظر %1$s @@ -1274,22 +1354,22 @@ رمز القفل تغيير رمز القفل - عندما تقوم بتعيين رمز قفل إضافي، ستظهر أيقونة قفل في صفحة المحادثات. اضغط عليها لقفل ولإلغاء قفل تطبيق تيليجرام.\n\nملاحظة: إن نسيت رمز القفل، ستحتاج لحذف وإعادة تنزيل التطبيق. وستخسر كافة محادثاتك السرية. + عندما تقوم بتعيين رمز قفل إضافي ستظهر أيقونة قفل أعلى صفحةِ المحادثات. اضغط عليها لإقفال تيليجرام أو فتْحِه.\n\nملحوظة: إذا نسيت رمز القفل فستحتاج لحذف التطبيق وإعادة تنزيله، ستفقد كافة محادثاتك السرية. رقم كلمة مرور قم بإدخال رمز قفلك الحالي قم بإدخال رمز قفل قم بإدخال رمز قفلك الجديد قم بإدخال رمز قفلك - قم بإعادة إدخال رمز قفلك الجديد + أعد إدخالَ رمز قفلك الجديد رموز القفل غير متطابقة - قفل تلقائي + القفل التلقائي طلب رمز القفل إن غِبتُ لفترةٍ ما. خلال %1$s معطّل إلغاء القفل عبر البصمة قم بتأكيد البصمة للاستمرار - حساس اللمس + مستشعر اللمس لم يتم التعرف على البصمة. حاول مرة أخرى السماح بتصوير الشاشة إن تم التفعيل، ستتمكن من تصوير الشاشة داخل التطبيق، لكن سيعرض النظام محادثاتك في شاشة تعدد المهام حتى في حال تفعيل رمز القفل.\n\nقد تحتاج لإعادة تشغيل التطبيق ليتم تفعيل هذا الخيار. @@ -1298,40 +1378,40 @@ ملفات وسائط روابط - موسيقى - صوتيات - الملفات المشاركة - الوسائط المشاركة - الروابط المشاركة - الموسيقى المشاركة - شارك الصور والمقاطع المرئية في هذه المحادثة للوصول إليها من أية جهاز من أجهزتك. - قم بإرسال مقاطع موسيقية لهذه المحادثة ليمكنك الوصول إليها من أجهزتك الأخرى. - شارك الملفات والمستندات في هذه المحادثة لتستطيع الوصول إليها من أية جهاز من أجهزتك - شارك الروابط في هذه المحادثة لتستطيع الوصول إليها من أية جهاز من أجهزتك - شارك الرسائل الصوتية في هذه المحادثة للوصول إليها من أية جهاز من أجهزتك. + صوتيات + تسجيلات + الملفات المتبادَلة + الوسائط المتبادَلة + الروابط المتبادَلة + الصوتيات المتبادَلة + شارك الصور والمقاطع المرئية في هذه المحادثة للوصول إليها عبر أي جهاز من أجهزتك. + قم بإرسال مقاطع صوتية إلى هذه المحادثة لتتمكن من الوصول إليها عبر أجهزتك الأخرى. + شارك الملفات والمستندات في هذه المحادثة لتتمكن من الوصول إليها عبر أي جهاز من أجهزتك. + شارك الروابط في هذه المحادثة لتتمكن من الوصول إليها عبر أي جهاز من أجهزتك. + شارك الرسائل الصوتية في هذه المحادثة للوصول إليها عبر أي جهاز من أجهزتك. الصور والمقاطع المرئية من هذه المحادثة ستظهر هنا. المقاطع الصوتية من هذه المحادثة سيتم عرضها هنا. الملفات والمستندات من هذه المحادثة سيتم عرضها هنا. - الروابط المشاركة من هذه المحادثة سيتم عرضها هنا. + سيتم عرض الروابط المتبادلة في هذه المحادثة هنا. ستجد الرسائل الصوتية من هذه المحادثة هنا. الخريطة قمر صناعي مختلطة - متر يبعد - كيلومتر يبعد + مترًا من هنا + ك.مترًا من هنا أرسل موقعك الحالي شارك موقعي الحي لمدة... إيقاف مشاركة الموقع - هل أنت متأكد من رغبتك في إيقاف مشاركة موقعك الحي مع %1$s? - هل أنت متأكد من رغبتك في إيقاف مشاركة موقعك الحي مع %1$s? + هل أنت متأكد من رغبتك في إيقاف مشاركة موقعك الحي مع %1$s؟ + هل أنت متأكد من رغبتك في إيقاف مشاركة موقعك الحي مع %1$s؟ هل أنت متأكد من رغبتك في إيقاف مشاركة موقعك الحي؟ يتم تحديثه مباشرةً أثناء تنقلك إرسال الموقع المختار الموقع مكان دقيق لدرجة %1$s - أو اختر مكان + أو اختر مكانًا اسحب للأعلى لمشاهدة الأماكن القريبة المواقع الحية لمدة 15 دقيقة @@ -1339,14 +1419,14 @@ لمدة 8 ساعات تم تحديثه محدث %1$s - تم تحديثه للتو - أنت و %1$s + تم تحديثه الآن + أنت و%1$s %1$s يتم مشاركته مع %2$s إيقاف الكل تقوم بمشاركة موقعك الحي مع %1$s - اختر المدة التي سيتمكن %1$s من مشاهدة موقعك الفعلي. - اختر المدة التي سيتمكن أعضاء هذه المحادثة من مشاهدة موقعك الفعلي. - يبدو أن تحديد المواقع معطّل لديك، يرجى تفعيله لاستخدام ميزات تيليجرام التي تتطلبه. + اختر المدة التي سيتمكن خلالها %1$s من مشاهدة موقعك الفعلي. + اختر المدة التي سيتمكن خلالها أعضاء هذه المحادثة من مشاهدة موقعك الفعلي. + يبدو أن تحديد المواقع معطّل لديك، يرجى تفعيله لاستخدام ميزات تيليجرام التي تحتاجه. عرض كافة الوسائط إظهار في المحادثة @@ -1356,30 +1436,30 @@ المعرض كافة الصور كافة الوسائط - لا توجد صور حتى الآن + لا توجد صور بعد فضلًا، قم بتنزيل الوسائط أولًا - يرجى الانتظار إلى حين تحميل كامل المقطع المرئي. + يرجى الانتظار إلى حين اكتمال تحميلِ المقطع المرئي. هذا المقطع المرئي غير مُخصصًا للبث. قد تحتاج إلى تحميله قبل مشاهدته. - لم يستطع التطبيق تشغيل هذا المقطع المرئي. هل تود تجربة تشغيله بمشغل خارجي؟ + لم يتمكن التطبيق من تشغيل هذا المقطع المرئي، هل ترغب في تشغيله بمشغل خارجي؟ لا توجد صور حديثة لا يوجد صور متحركة حديثة بحث الصور بحث على الإنترنت بحث الصور المتحركة بحث على الإنترنت - بحث الصور المتحركة + بحث عن صور متحركة قص الصورة تحسين التفتيح التباين - تكشيف + تفتيح الدفء التشبع نقش الظلال حبوب زيادة الحدة - تلاشي + التلاشي الظلال الإضاءات الكل @@ -1388,7 +1468,7 @@ أزرق إيقاف طولي - قطري + قُطري هل أنت متأكد من رغبتك في حذف هذه الصورة؟ هل أنت متأكد من رغبتك في حذف هذا المقطع المرئي؟ تجاهل التغييرات؟ @@ -1405,14 +1485,14 @@ مرسوم عادي إعادة تعيين - الأصل + الأصلي مربع - إرسال الوسائط كرسائل متفرقة + إرسال الوسائط في رسائل متفرقة تجميع الوسائط في رسالة واحدة التحقق بخطوتين تعيين كلمة مرور إضافية - يمكنك تعيين كلمة مرور يتم طلبها عند محاولة تسجيل الدخول من جهاز جديد بالإضافة إلى الرمز الذي يأتيك في رسالة قصيرة. + يمكنك تعيين كلمة مرور إضافية يتم طلبها عند تسجيل الدخول من جهاز غير معروف، إضافةً إلى الرمز الذي يصلك في رسالة قصيرة. كلمة مرورك يرجى إعادة إدخال كلمة المرور الخاصة بك: قم بإدخال كلمة مرور @@ -1420,13 +1500,13 @@ يرجى إعادة إدخال كلمة المرور الخاصة بك: بريد الاسترداد بريدك الإلكتروني - فضلًا قم بإضافة بريدًا إلكترونيًا صحيحًا. هذه هي الطريقة الوحيدة لاستعادة كلمة مرور منسية. - تخطي + فضلًا قم بإضافة بريد إلكتروني صالح، هذه هي الطريقة الوحيدة لاستعادة كلمة المرور المنسية. + تجاوز تحذير - الموضوع جدّيّ.\n\nإن نسيت كلمة مرورك، ستفقد الوصول لحسابك في تيليجرام. لن يكون هناك أي طريقة لاستعادته. - تقريبًا انتهينا! - يرجى الذهاب لبريدك الإلكتروني والضغط على رابط التأكيد لإنهاء إعدادات التحقق بخطوتين. تأكد من الإطّلاع على مجلد الرسائل غير المرغوب بها أيضًا. - تم بنجاح! + المخاطرة حقيقية!\n\nإن نسيتَ كلمة مرورك، ستفقد الوصول لحسابك في تيليجرام، لن يكون هناك أي طريقة لاستعادته. + انتهينا تقريبًا! + يرجى تفقُّد بريدك الإلكتروني والضغطُ على رابط التأكيد لإتمام تفعيل التحقق بخطوتين. قم بتفقُّد مجلدِ الرسائل غير المرغوب بها أيضًا. + نجح الأمر! تم تفعيل كلمة المرور الخاصة بالتحقق بخطوتين. تغيير كلمة المرور إيقاف كلمة المرور @@ -1435,17 +1515,17 @@ هل أنت متأكد من رغبتك في تعطيل كلمة مرورك؟ تحذير! سيتم فقدان جميع البيانات المحفوظة في جواز تيليجرام! تلميح كلمة المرور - يرجى إنشاء تلميحًا لكلمة مرورك - كلمتا المرور غير متطابقة + قم بإنشاء تلميحٍ لكلمة مرورك + كلمتا المرور غير متطابقتين إلغاء عملية إعداد التحقق بخطوتين - فضلًا اتّبع هذه الخطوات لإكمال إعدادات التحقق بخطوتين:\n\n١. قم بالإطلاع على بريدة الإلكتروني بما فيه مجلد الرسائل غير المرغوب بها\n%1$s\n\n٢. اضغط على رابط التأكيد + لإكمال عملية إعدادِ التحقق بخطوتين قم بما يلي رجاءً:\n\n١. تفقَّد بريدك الإلكتروني %1$s (بما في ذلك مجلد الرسائل غير المرغوب فيها).\n\n٢. اضغط على رابط التأكيد. يجب أن يكون التلميح مختلفًا عن كلمة مرورك بريد إلكتروني غير صحيح المعذرة بما أنك لم تقم بإضافة بريدًا إلكترونيًا لاسترداد حسابك عند تعيين كلمة مرورك فإن خياراتك المتبقية هي إما تذكّر كلمة مرورك أو إعادة تعيين حسابك. إعادة تعيين الحساب - لقد قمنا بإرسال رمز الإستعادة إلى بريدك الإلكتروني الذي اخترته مسبقًا:\n\n%1$s - يرجى الإطلاع على بريدك وإدخال الرمز المكون من 6 أرقام الذي أرسلناه. + لقد قمنا بإرسال رمز الاستعادة إلى بريدك الإلكتروني الذي اخترته مسبقًا:\n\n%1$s + يرجى تفقُّد بريدك وإدخال رمز التفعيل الذي قمنا بإرساله والمكون من 6 أرقام. هل تواجه صعوبات في الدخول إلى بريدك %1$s؟ إن لم تستطع الوصول إلى البريد الإلكتروني، فإن خياراتك المتبقية هي إما أن تتذكر كلمة المرور الخاصة بك أو أن تعيد تعيين حسابك. إعادة تعيين حسابي @@ -1459,28 +1539,28 @@ استرداد كلمة المرور الرمز تم تعطيل كلمة المرور - لقد قمت بتفعيل التحقق بخطوتين.\nستحتاج لكلمة المرور التي عينتها لكي تسجل دخولك إلى حسابك في تيليجرام من أجهزة جديدة. - بريد الاسترداد الخاص بك %1$s غير فعّال بعد ويلزم تفعيله. + لقد قمت بتفعيل التحقق بخطوتين.\nلتسجيل الدخول إلى حسابك هذا من أجهزة جديدةٍ ستحتاج إلى كلمة المرور التي قمت بتعيينها. + بريد الاسترداد الخاص بك %1$s غير مفعل ويَلزمك تفعيله عبر الرسالة الواردة إليه. البيانات والتخزين استخدام الشبكة والتخزين استخدام التخزين استخدام بيانات الجوال - استخدام تجوال البيانات + استخدام بيانات التجوال استخدام بيانات Wi-Fi الرسائل والبيانات الأخرى المرسلة الواردة البايتات المرسلة البايتات الواردة - ملفات + الملفات المكالمات المكالمات صادرة - المكالمات واردة - إجمالي الوقت - إجمالي + المكالمات الواردة + الوقت الإجمالي + الإجمالي إعادة تعيين الإحصائيات - استخدام خلوي منذ %1$s + إحصاءات الاستخدام منذ %1$s هل ترغب في مسح إحصائيات استخدامك؟ الخصوصية والأمان @@ -1488,12 +1568,12 @@ آخر ظهور البوتات والمواقع مسح معلومات الدفع والشحن - حذف معلومات الشحن والطلب الخاصة بك والطلب من موردي خدمات الدفع حذف بطاقتك الائتمانية المحفوظة؟ اعلم أن تيليجرام لا يحفظ بيانات بطاقتك الائتمانية أبدًا. - المواقع التي استخدمت تيليجرام لتسجيل الدخول إليها. + حذفُ معلومات الشحن الخاصة بك، ومطالبةُ موفِّري خدمات الدفع بحذف بطاقاتك الائتمانية المحفوظة؟ اعلم أن تيليجرام لا يحفظ بيانات بطاقتك الائتمانية أبدًا. + المواقع التي سجلتَ دخولك إليها عبر تيليجرام. معلومات الشحن معلومات الدفع حذف جميع المسودات السحابية - الجميع + أي أحد جهات اتصالي لا أحد الجميع (-%1$d) @@ -1503,39 +1583,39 @@ لا أحد (+%1$d) الأمان التدمير الذاتي للحساب - متخصصة + إعدادات متقدمة حذف حسابي إن غِبتُ لمدة - إن لم تقم بفتح تيليجرام لمرة واحدة على الأقل خلال هذه الفترة، سيتم حذف حسابك بالإضافة إلى جميع رسائلك وجهات اتصالك. + إذا لم تستخدم حسابَ تيليجرام هذا لمرة واحدة على الأقل خلالَ هذه المدة فسيتم حذفه نهائيًا مع جميع محادثاتك وجهات اتصالك. من يستطيع رؤية آخر ظهور لك؟ إضافة استثناءات - هام: لن تستطيع رؤية آخر ظهور للأشخاص الذين اخترت ألا يروا آخر ظهور لك. سيتم عرض آخر ظهور تقريبي كبديل (قريبًا، خلال أسبوع، خلال شهر). + هام: لن تستطيع رؤية آخر ظهور للأشخاص الذين اخترت ألا يروا آخر ظهور لك.\nسيتم بدلًا من ذلك عرض آخر ظهور تقريبي (شُوهدَ مؤخرًا، خلال أسبوع، خلال شهر). المشاركة دائمًا مع عدم المشاركة مع - هذه الإعدادات ستتجاوز القيم في الأعلى. + ستتجاوز هذه الإعدادات القيم في الأعلى. المشاركة دائمًا مع المشاركة مع هؤلاء دائمًا... عدم المشاركة مع عدم المشاركة مع هؤلاء مطلقًا... إضافة مستخدمين - عذرًا، لقد قمت بالعديد من الطلبات. لا تستطيع تغيير إعدادات الخصوصية الآن، يرجى الانتظار. - إضغط باستمرار على المستخدم لحذفه + عذرًا، لقد قمت بطلبات كثيرة جدًا. لا يمكنك تغيير إعدادات الخصوصية الآن، يرجى الانتظار. + اضغط باستمرار على المستخدم لإزالته المجموعات من يستطيع إضافتي للمجموعات؟ - بإمكانك اختيار من يستطيع إضافتك إلى المجموعات والقنوات بدقة انتقائية. + بإمكانك تحديد الأشخاص المسموح لهم بإضافتك إلى المجموعات والقنوات بشكل تفصيلي. السماح دائمًا عدم السماح أبدًا السماح دائمًا لـ... عدم السماح مطلقًا لـ... - هؤلاء المستخدمين يمكنهم أو لا يمكنهم إضافتك للمجموعات والقنوات بغض النظر عن الأعدادات أعلاه. - غيّر من يستطيع إضافتك للمجموعات والقنوات. + هؤلاء المستخدمون سيتم السماح لهم بإضافتك للمجموعات والقنوات أو منعُهم من ذلك بغض النظر عن الإعدادات أعلاه. + غيّر الذين بإمكانهم إضافتك للمجموعات والقنوات. المعذرة، لا يمكنك إضافة هذا المستخدم للمجموعات بسبب إعدادات الخصوصية المتعلقة به. المعذرة، لا يمكنك إضافة هذا المستخدم للقنوات بسبب إعدادات الخصوصية المتعلقة به. المعذرة، لا يمكنك إنشاء مجموعة مع هؤلاء المستخدمين نظرًا لإعدادات خصوصيتهم. - الند للند - تعطيل الند للند سيجعل جميع المكالمات تعتمد على خوادم تيليجرام لتجنب الإفصاح عن الـ IP الخاص لك، لكن ستنخفض جودة الصوت قليلًا. - حذف الجهات المتزامنة + النِّد للنِّد + تعطيل خيار النِّد للنِّد سيجعل جميع المكالمات معتمِدةً على خوادم تيليجرام لحماية عنوان الـ IP الخاص بك، لكن بالمقابل ستنخفض جودةُ الصوت قليلًا. + حذف الجهات المزامَنة اقتراح الجهات المتكررة - عرض الأشخاص الذين تراسلهم كثيرًا أعلى قسم البحث للوصول السريع. + عرضُ الأشخاص الذين تراسلهم باستمرار في أعلى خانة البحث للوصول إليهم بشكل أسرع. سيؤدي هذا إلى حذف جميع البيانات المتعلقة بالأشخاص الذين تراسلهم بشكل متكرر بالإضافة إلى البوتات الاستعلامية التي قد تستخدمها. جارٍ إرسال المقطع المرئي... @@ -1548,7 +1628,7 @@ مساعدة يمكنه الوصول للرسائل لا يمكنه الوصول للرسائل - ماذا يمكن لهذا البوت فعله؟ + ما الذي يقدمه هذا البوت؟ ابدأ إعادة تشغيل إيقاف البوت @@ -1587,51 +1667,51 @@ تسجيل رفض وحذف الحساب - لقد انضممت للمجموعة عبر رابط دعوة + انضممتَ للمجموعة عبر رابط دعوة un1 انضم للمجموعة عبر رابط دعوة un1 أزال un2 un1 غادر المجموعة un1 أضاف un2 - un1 أزال صورة المجموعة - تم تغيير صورة المجموعة من قِبَل un1 - un1 غيّر اسم المجموعة إلى un2 + أزال un1 صورة المجموعة + غيّر un1 صورة المجموعة + غيّر un1 اسم المجموعة ليصبح un2 un1 انشأ المجموعة لقد أزلت un2 أنت غادرت المجموعة لقد قمت بإضافة un2 قمت بإحراز %1$s - un1 أحرز %1$s + أحرز un1 %1$s قمت بإحراز %1$s في un2 un1 أحرز %1$s في un2 - لقد قمت بإزالة صورة المجموعة - لقد قمت بتغيير صورة المجموعة - لقد قمت بتغيير اسم المجموعة إلى un2 - لقد قمت بإنشاء المجموعة + لقد أزلتَ صورة المجموعة + لقد غيّرتَ صورة المجموعة + لقد غيّرتَ اسم المجموعة ليصبح un2 + لقد أنشأت المجموعة un1 أزالك un1 قام بإضافتك un1 عاد إلى المجموعة un1 انضم للمجموعة - لقد عدت إلى المجموعة + لقد عُدتَ إلى المجموعة لقد سمحت لهذا البوت بمراسلتك عندما تسجل دخولك إلى %1$s استلم %1$s الوثائق التالية: %2$s التفاصيل الشخصية العنوان - جواز + جواز السفر جواز داخلي تسجيل الجواز تسجيل مؤقت - رخصة قيادة - بطاقة هوية شخصية + رخصة القيادة + بطاقة الهوية الشخصية فاتورة خدمية - كشف رصيد بنكي + كشفُ حسابٍ مصرفي عقد الإيجار رقم الهاتف بريد إلكتروني - نسخة تيليجرام الموجودة لديك لا تدعم هذه الرسالة. الرجاء التحديث لأحدث نسخة: https://telegram.org/update + نسختك الحالية من تيليجرام لا تدعم هذه الرسالة؛ رجاء قم بتحديث التطبيق: https://telegram.org/update صورة مقطع مرئي - صورة بتدمير ذاتي - مقطع مرئي بتدمير ذاتي + صورة ذاتية التدمير + مقطع مرئي ذاتي التدمير انتهت صلاحية الصورة انتهت صلاحية المقطع المرئي صورة متحركة @@ -1648,21 +1728,21 @@ un1 صوّر الشاشة! تحديث تيليجرام - عذرًا، أصبح تطبيق تيليجرام الذي تملكه قديمًا ولا يمكنه التعامل مع هذا الطلب. يرجى تحديثه. + عذرًا، تطبيق تيليجرام الذي تملكه قديم ولا يمكنه التعامل مع هذا الطلب، يرجى القيام بتحديثه. رقم الهاتف غير صحيح - يرجى تسجيل الدخول لحسابك في تيليجرام لتستطيع استخدام جواز تيليجرام. + يرجى تسجيل الدخول إلى حسابك في تيليجرام لتتمكن من استخدام جواز تيليجرام. رقم الهاتف محظور انتهت صلاحية الرمز الخاص بك، يرجى تسجيل الدخول مرة أخرى محاولات كثيرة خاطئة، نرجو المحاولة لاحقًا محاولات كثيرة خاطئة، يرجى المحاولة خلال %1$s الرمز غير صحيح - المعذرة، لقد قمت بحذف حسابك وإعادة إنشاؤه عدة مرات مؤخرًا. فضلًا انتظر لعدة أيام قبل محاولة إنشاء الحساب من جديد. + المعذرة، لقد قمت بحذف حسابك وإعادة إنشائه عدة مرات مؤخرًا، انتظر لعدة أيام رجاءً قبل محاولة إنشاء الحساب من جديد. الاسم الأول غير صحيح اسم العائلة غير صحيح جارٍ التحميل... - ليس لديك أي مشغل مقاطع مرئية، يرجى تنزيل أية مشغل - يرجى إرسال رسالة بواسطة البريد الإلكتروني إلى sms@stel.com لتخبرنا عن مشكلتك. - لا يوجد لديك تطبيق يمكنه فتح \'%1$s\'، يرجى تنزيل تطبيق مناسب للاستمرار + لا تملك أي مشغل للمقاطع المرئية على جهازك، يرجى تنزيل واحد للمتابعة + يرجى مراسلتنا عبر البريد الإلكتروني sms@stel.com لإخبارنا بمشكلتك. + لا تملك تطبيقًا يمكنه فتح صيغة الملفات \'%1$s\'، يرجى تنزيل تطبيق مناسب للاستمرار هذا المستخدم ليس لديه تيليجرام بعد ، هل ترغب في دعوته الآن؟ هل أنت متأكد؟ هل ترغب بإضافة %1$s للمحادثة %2$s؟ @@ -1671,39 +1751,39 @@ إرسال الرسائل إلى %1$s؟ هل ترغب في مشاركة اللعبة مع %1$s؟ إرسال جهة الاتصال إلى %1$s؟ - نرجو الأخذ بالعلم أنه يمكنك استخدام تيليجرام على أجهزتك المتعددة بسهولة تامة وفي وقت واحد.\n\nوتذكر، تسجيل الخروج يحذف كافة محادثاتك السرية. + هل أنت متأكد من رغبتك في تسجيل الخروج؟\n\nتذكَّر أنه يمكنك استخدام تيليجرام على جميع أجهزتك في ذات الوقت بسهولة تامة.\n\nولا تنسَ أن تسجيل الخروج سيحذف كل محادثاتك السرية. هل أنت متأكد من أنك تريد حذف المجموعة والخروج منها؟ - هل أنت متأكد أنك تريد حذف هذه المحادثة؟ + هل أنت متأكد من رغبتك في حذف هذه المحادثة؟ هل أنت متأكد من رغبتك في حذف جميع المسودات السحابية؟ هل ترغب في مشاركة موقعك؟ بهذه العملية سترسل موقعك الحالي للبوت. - لا يستطيع التطبيق تحديد موقعك الحالي + التطبيق غير قادر على تحديد موقعك الحالي اختر بشكل يدوي - يرغب هذا البوت في معرفة موقعك عند كل مرة ترسل له طلب. يمكن الاستفادة من هذا لإعطائك نتائج مخصصة لموقعك. + يرغب هذا البوت بمعرفة موقعك عند كل مرة ترسل له طلبًا، يمكن استخدام هذا لتوفير نتائجَ مخصصةٍ لموقعك. هل ترغب في مشاركة رقم هاتفك؟ - البوت سيعلم رقم هاتفك. سيكون هذا مفيد لتفعيله في خدمات أخرى. + سيطلع البوت على رقم هاتفك. ربما يكون هذا مفيدًا للتكامل مع خدمات أخرى. هل أنت متأكد من رغبتك في مشاركة رقم هاتفك %1$s مع **%2$s**؟ هل أنت متأكد من رغبتك في مشاركة رقم هاتفك؟ هل أنت متأكد من رغبتك في حظر جهة الاتصال هذه؟ هل أنت متأكد من رغبتك في إزالة الحظر عن جهة الاتصال هذه؟ هل أنت متأكد من رغبتك في حذف جهة الاتصال هذه؟ - هل أنت متأكد من أنك تريد بدء محادثة سرية؟ + هل أنت متأكد من رغبتك في بدءِ محادثة سرية؟ هل أنت متأكد من رغبتك في إلغاء التسجيل؟ هل أنت متأكد من رغبتك في حذف سجل المحادثات؟ - حذف كافة المحادثات والوسائط المتعلقة بهذه القناة من الذاكرة المخبئية؟ - حذف جميع الرسائل والوسائط من الذاكرة المخبئية للمجموعة هذه؟ + حذف كافة المحادثات والوسائط المتعلقة بهذه القناة من الذاكرة المؤقتة؟ + حذف جميع الرسائل والوسائط المخزنة مؤقتًا من هذه المجموعة؟ هل أنت متأكد من رغبتك في حذف %1$s؟ إرسال الرسائل إلى %1$s؟ هل ترغب في مشاركة اللعبة مع %1$s؟ إرسال جهة الاتصال إلى %1$s؟ لا يوجد حساب تيليجرام بهذا الاسم. - لا يمكن لهذا البوت الانضمام للمجموعات. + لا يمكن أن يضافَ هذا البوت إلى المجموعات. هل ترغب في تفعيل معاينة الروابط المطولة في المحادثات السرية؟ علمًا أنه يتم توليدها في خوادم تيليجرام. يرجى ملاحظة أن بوتات المحتوى الاستعلامي يتم تطويرها من مطورين مستقلين. لكي تعمل هذه البوتات، ما تكتبه بعد اسم مستخدم البوت يذهب لمطور البوت. - المعذرة، لا يمكنك التعديل على هذه الرسالة. - فصلًا قم بالسماح لتيليجرام باستقبال رسائل قصيرة ليتمكن من إدخال الرمز لك تلقائيًا. + المعذرة، لا يمكنك تعديل هذه الرسالة. + فضلًا قم بالسماح لتيليجرام بتلقي الرسائل القصيرة ليتمكن من تفعيل حسابك تلقائيًا. فصلًا قم بالسماح لتيليجرام باستقبال اتصالات ليتمكن من إدخال الرمز لك تلقائيًا. - فصلًا قم بالسماح لتيليجرام باستقبال اتصالات ورسائل قصيرة ليتمكن من إدخال رقمك، إرسال رمز التفعيل إليك، وإدخال الرمز لك تلقائيًا. + فضلا قم بالسماح لتيليجرام بتلقي المكالمات والرسائل القصيرة ليتمكن من طلبِ الرمز وإدخاله لك تلقائيًا لتفعيل حسابك. فصلًا قم بالسماح لتيليجرام باستقبال اتصالات ورسائل قصيرة ليتمكن من إدخال الرمز لك تلقائيًا. المعذرة، لا يمكنك القيام بذلك. المعذرة، لا يمكنك إضافة هذا المستخدم أو البوت للمجموعات بسبب أنك قمت بحظره. فضلًا قم بإزالة الحظر للاستمرار. @@ -1713,21 +1793,21 @@ المعذرة، لا يمكنك حظر هذا المستخدم لأنه مشرف في هذه المجموعة ولا يمكنك تغيير ذلك. المعذرة، مشرفو هذه المجموعة قيدوك من إرسال الملصقات. المعذرة، مشرفو هذه المجموعة قيدوك من إرسال الوسائط. - نحن متأسفون للغاية، ولكن هذا يعني أنه لا يمكنك الاشتراك بتيليجرام.\n\nعلى عكس الآخرين، نحن لا نستخدم بياناتك لاستهدافك بالإعلانات أو لأغراض تجارية أخرى. لا يخزن تيليجرام سوى المعلومات التي يحتاجها ليعمل كخدمة سحابية غنية بالميزات. يمكنك ضبط كيفية استخدامنا لبياناتك (مثل إعدادات حذف الجهات المتزامنة) في إعدادات الخصوصية والأمان.\n\nلكن إن كنت غير موافق على احتياجات تيليجرام المتواضعة بشكل عام، فلن يكون من الممكن لنا تقديم هذه الخدمة. + نحن متأسفون للغاية، ولكن هذا يعني أنه لا يمكنك الاشتراك بتيليجرام.\n\nعلى عكس الآخرين، نحن لا نستخدم بياناتك لاستهدافك بالإعلانات أو لأغراض تجارية أخرى. لا يخزن تيليجرام سوى المعلومات التي يحتاجها ليعمل كخدمة سحابية غنية بالميزات. يمكنك ضبط كيفية استخدامنا لبياناتك (مثل إعدادات حذف الجهات المزامَنة) في إعدادات الخصوصية والأمان.\n\nلكن إن كنت غير موافق على احتياجات تيليجرام المتواضعة بشكل عام، فلن يكون من الممكن لنا تقديم هذه الخدمة. التحقق من العمر سياسة الخصوصية وشروط الخدمة اضغط موافق للتأكيد بأن عمرك %1$s أو أكثر. - نحن متأسفون للغاية، ولكن هذا يعني أنه يجب علينا الافتراق. على عكس الآخرين، نحن لا نستخدم بياناتك لاستهدافك بالإعلانات أو لأغراض تجارية أخرى. لا يخزن تيليجرام سوى المعلومات التي يحتاجها ليعمل كخدمة سحابية غنية بالميزات. يمكنك ضبط كيفية استخدامنا لبياناتك (مثل إعدادات حذف الجهات المتزامنة) في إعدادات الخصوصية والأمان.\n\nلكن إن كنت غير موافق على احتياجات تيليجرام المتواضعة بشكل عام، فلن يكون من الممكن لنا تقديم هذه الخدمة. يمكنك حذف حسابك الآن — أو قم بالإطلاع أكثر ومن ثم حذفه لاحقًا إن كنت تشعر أنك غير راضي عن الطريقة التي نستخدم بها بياناتك. + نحن متأسفون للغاية، ولكن هذا يعني أنه يجب علينا الافتراق. على عكس الآخرين فنحن لا نستخدم بياناتك لاستهدافك بالإعلانات أو لأغراض تجارية أخرى. لا يخزن تيليجرام سوى المعلومات التي يحتاجها ليعمل كخدمة سحابية غنية بالميزات. يمكنك التحكم بكيفية استخدامنا لبياناتك (مثل إعدادات حذف الجهات المزامَنة) في إعدادات الخصوصية والأمان.\n\nلكن إن كنت غيرَ موافق على احتياجات تيليجرام المتواضعة بشكل عام، فلن يكون بإمكاننا تقديم هذه الخدمة. يمكنك حذف حسابك الآن — أو القيام بالإطلاع أكثر ومن ثَم حذفِه لاحقًا إن كنت تشعر بعدم الرضى عن الطريقة التي نستخدم بها بياناتك. تحذير، سيؤدي هذا إلى حذف حسابك في تيليجرام بشكل نهائي بالإضافة لجميع البيانات التي تخزنها في سحابة تيليجرام.\n\nهام: يمكنك الإلغاء الآن وتصدير بياناتك قبل حذف حسابك عوضًا عن خسارتها كلها. (للقيام بذلك، افتح النسخة الأخيرة من تيليجرام لسطح المكتب وتوجه إلى الإعدادات > تصدير بيانات تيليجرام.) - يحتاج تيليجرام إلى الوصول لجهات اتصالك لكي تستطيع التواصل مع أصدقائك عبر جميع أجهزتك. - تيليجرام يحتاج للسماح له بالوصول للذاكرة الخاصة بك لتتمكن من إرسال وحفظ الصور، المقاطع المرئية، الموسيقى وغيرها من الوسائط. - تيليجرام يحتاج للسماح له بالوصول للمايكروفون الخاص بك لتتمكن من إرسال رسائل صوتية. - يحتاج تيليجرام صلاحيات الوصول للمايكروفون الخاص بك لتتمكن من إرسال المقاطع المرئية. - تيليجرام يحتاج للسماح له بالوصول للكاميرا لتتمكن من التقاط صور ومقاطع مرئية. - يحتاج تيليجرام أذن الوصول إلى موقعك لتتمكن من مشاركته مع أصدقائك. - تيليجرام يحتاج صلاحية الحصول على موقعك. - يحتاج تيليجرام الأذن ليشغل المقاطع المرئية في وضع الصورة داخل الصورة بعد الخروج منه. + يحتاج تيليجرام إلى الوصول لجهات اتصالك لتتمكن من التواصل مع أصدقائك عبر جميع أجهزتك. + يحتاج تيليجرام إلى السماح له بالوصول لذاكرة التخزين لتتمكن من إرسال وحفظ الصور، المقاطع المرئية، الصوتيات وغيرها من الوسائط. + يحتاج تيليجرام إلى السماح له بالوصول للمايكروفون الخاص بك لتتمكن من إرسال رسائل صوتية. + يحتاج تيليجرام إلى صلاحية الوصول للمايكروفون الخاص بك لتتمكن من تسجيل المقاطع المرئية. + يحتاج تيليجرام إلى السماح له بالوصول للكاميرا لتتمكن من التقاط الصور والمقاطع المرئية. + يحتاج تيليجرام إلى السماح له بتحديد موقعك لتتمكن من مشاركته مع أصدقائك. + يحتاج تيليجرام إلى صلاحية تحديد موقعك. + يحتاج تيليجرام إلى صلاحية الظهور فوق التطبيقات لتشغيل المقاطع المرئية في وضع (صورة في الصورة). الإعدادات تيليجرام @@ -1745,7 +1825,7 @@ ابدأ المراسلة إعدادات الحساب - استخدام بيانات أقل للمكالمات + توفير بيانات المكالمات مكالمة واردة جارٍ الاتصال جارٍ مبادلة مفاتيح التشفير @@ -1760,20 +1840,20 @@ مكالمة تيليجرام الحالية إنهاء المكالمة مكالمة أخرى نشطة - لديك حاليًا مكالمة نشطة مع **%1$s**. هل ترغب في إنهاء المكالمة وبدء مكالمة جديدة مع **%2$s**؟ + لديك حاليًا مكالمة نشطة مع **%1$s**. هل ترغب في إنهائها وبدءِ مكالمة جديدة مع **%2$s**؟ المكالمات الصوتية "نغمة الرنين " يمكنك تخصيص نغمة الرنين عندما يتصل بك هذا المستخدم في تيليجرام. المكالمات من يستطيع الاتصال بي؟ يمكنك تخصيص من يستطيع الاتصال بك. - هؤلاء المستخدمين بإمكانهم أو ليس بإمكانهم الاتصال بك بغض النظر عن الإعدادات أعلاه. + هؤلاء المستخدمون سيتم السماح لهم بالاتصال بك أو منعُهم من ذلك بغض النظر عن الإعدادات أعلاه. مطلقًا فقط على البيانات الخلوية دائمًا - رد + إجابة رفض - أنت غير متصل حاليًا. قم بالاتصال بالانترنت لتتمكن من إجراء مكالمات. + أنت غير متصل حاليًا، قم بالاتصال بالإنترنت لتتمكن من إجراء المكالمات. لقد قمت بتفعيل وضع الطيران. يرجى تعطيله أو الاتصال بشبكة Wi-Fi لتتمكن من إجراء المكالمات. غير متصل وضع الطيران @@ -1781,13 +1861,13 @@ مكالمة صادرة مكالمة واردة مكالمة فائتة - مكالمة ملغاة + مكالمة مُلغَاة مكالمة مرفوضة %1$s (%2$s) - لم تقم بإجراء أية مكالمة بعد. - إصدار تيليجرام الخاص بـ**%1$s** غير متوافق. ينبغي عليه تحديث إصدارهم لتتمكن من الاتصال بهم. - تطبيق %1$s لا يدعم المكالمات. يتوجب عليه تحديث تطبيقه قبل أن تتمكن من الاتصال به. - فضلًا قم بتقييم مكالمتك في تيليجرام + لم تقم بإجراء أي مكالمة بعد. + يستخدم تطبيق تيليجرام الخاص بـ**%1$s** بروتوكولًا غيرَ متوافقٍ، ينبغي عليهم تحديث تطبيقهم لتتمكن من الاتصال بهم. + نسخة **%1$s** لا تدعم المكالمات؛ يَلزمُه تحديث تطبيقه قبل أن تتمكن من الاتصال به. + فضلًا قم بتقييم جودة اتصالك في تيليجرام تيليجرام يحتاج للسماح له بالوصول للمايكروفون الخاص بك لتتمكن من إجراء مكالمات. إضافة تعليق اختياري معاودة الاتصال @@ -1800,29 +1880,29 @@ بلوتوث الرجوع للمكالمة المعذرة، **%1$s** لا يستقبل مكالمات. - إذا كانت هذه الإيموجيات مطابقة للتي تظهر على شاشة %1$s فالمكالمة آمنة 100%%. + إذا كانت هذه الرموز مطابقة للتي تظهر على شاشة %1$s فالمكالمة آمنة 100%%. قيم المكالمة ماذا حدث؟ - أرفق المعلومات التقنية + تضمين المعلومات التقنية هذا لن يفصح عن محتوى محادثتك، لكن سيساعد في حل المشكلة بشكل أسرع. - شكرًا لمساعدتك في جعل مكالمات تيليجرام أفضل. - سيتم الرد كـ %s + شكرًا لمساهمتك في تحسين مكالمات تيليجرام. + سيتم الرد باسم %s الرد برسالة - هذه الردود السريعة ستكون متاحة لك للرد على مكالمات تيليجرام برسائل تيليجرام. يمكنك تغييرها لما تحب. - لا أستطيع التكلم الآن. ما الأمر؟ + ستكون هذه الردود السريعة متاحة لك للرد على مكالمات تيليجرام برسائل داخل التطبيق، يمكنك تغييرها لما يناسبك. + لا يمكنني التحدثُ الآن، ما الأمر؟ سأعاود الاتصال بك لاحقًا. سأتصل بك لاحقًا. - لا أستطيع التكلم الآن. نتكلم لاحقًا؟ + لا يمكنني التحدث الآن، نتحدث لاحقًا؟ رسالة مخصصة... السماح برسائل مخصصة - مكالمة تيليجرام إلى %s + مكالمة تيليجرام مع %s لا يمكن إجراء مكالمة تيليجرام حاليًا. - لا يوجد مستقبلين + لا يوجد مستقبلون مستقبل واحد مستقبلان - %1$d مستقبلون - %1$d مستقبل + %1$d مستقبلين + %1$d مستقبلًا %1$d مستقبل %1$d متصل %1$d متصل @@ -1832,43 +1912,43 @@ %1$d متصل لا يوجد جهات اتصال على تيليجرام جهة اتصال واحدة على تيليجرام - جهتي اتصال على تيليجرام + جهتا اتصال على تيليجرام %1$d جهات اتصال على تيليجرام %1$d جهة اتصال على تيليجرام %1$d جهة اتصال على تيليجرام - "مرحبا، أنا استخدم تيليجرام للمحادثة - انضم إلينا من هنا: %2$s " - "مرحبا، أنا استخدم تيليجرام للمحادثة - كذلك جهة اتصال أخرى. انضم إلينا من هنا: %2$s " - "مرحبا، أنا استخدم تيليجرام للمحادثة - كذلك جهتي اتصال أخرى. انضم إلينا من هنا: %2$s " - "مرحبا، أنا استخدم تيليجرام للمحادثة - كذلك %1$d جهات اتصال أخرى. انضم إلينا من هنا: %2$s " - "مرحبا، أنا استخدم تيليجرام للمحادثة - كذلك %1$d جهة اتصال أخرى. انضم إلينا من هنا: %2$s " - مرحبا، أنا استخدم تيليجرام للمحادثة - كذلك %1$d جهة اتصال أخرى. انضم إلينا من هنا: %2$s - صفر + "مرحبا، أنا أستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s " + "مرحبا، أنا وإحدى جهات اتصالي نستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s " + "مرحبا، أنا و%1$d من جهات اتصالي نستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s " + "مرحبا، أنا و%1$d من جهات اتصالي نستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s " + "مرحبا، أنا و%1$d من جهات اتصالي نستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s " + مرحبا، أنا و%1$d من جهات اتصالي نستخدم تيليجرام للمحادثة - يمكنك تنزيله من هنا: %2$s + %1$d محادثة محادثة واحدة - محادثتين + محادثتان %1$d محادثات %1$d محادثة %1$d محادثة %1$d أعضاء - %1$d عضو - %1$d عضوان + عضو واحد + عضوان %1$d أعضاء - %1$d عضو + %1$d عضوًا %1$d عضو - كذلك %1$d عضو آخر يقوب بالكتابة - كذلك %1$d عضو آخر يقوم بالكتابة - كذلك %1$d عضوان آخران يقومان بالكتابة - كذلك %1$d أعضاء آخرون يقومون بالكتابة - كذلك %1$d عضو آخرون يقومون بالكتابة - كذلك %1$d عضو آخرون يقومون بالكتابة + و%1$d يكتب الآن + وعضوٌ آخرُ يكتبان الآن + وعضوان آخَران يكتبون الآن + و%1$d أعضاء آخَرين يكتبون الآن + و%1$d عضوًا آخَرين يكتبون الآن + و%1$d آخَرون يكتبون الآن - %1$s و شخص اخر يقوموا بالكتابة - %1$s و شخصان يقوموا بالكتابة - %1$s و %2$d أشخاص يقوموا بالكتابة - %1$s و %2$d شخص يقوموا بالكتابة - %1$s و %2$d شخص يقوموا بالكتابة - لا يوجد رسائل جديدة - %1$d رسالة جديدة - %1$d رسالتان جديدتان + %1$s و شخص اخر يكتبان + %1$s و شخصان آخران يكتبون + %1$s و %2$d أشخاص آخرين يكتبون + %1$s و %2$d شخصا آخر يكتبون + %1$s و %2$d شخص آخر يكتبون + لا توجد رسائل جديدة + رسالة واحدة جديدة + رسالتان جديدتان %1$d رسائل جديدة %1$d رسالة جديدة %1$d رسالة جديدة @@ -1878,15 +1958,15 @@ %1$d رسائل %1$d رسالة %1$d رسالة - لا يوجد ملفات - %1$d ملف - %1$d ملف - %1$d ملفات - %1$d ملف - %1$d ملف - من ولا محادثة - من %1$d محادثة - من %1$d محادثة + %1$d عنصر + عنصر واحد + عنصرَين + %1$d عناصر + %1$d عنصرًا + %1$d عنصر + من %1$d محادثة + من محادثة واحدة + من محادثتين من %1$d محادثات من %1$d محادثة من %1$d محادثة @@ -1897,8 +1977,8 @@ %1$d ثانية %1$d ثانية %1$d دقيقة - %1$d دقيقة - %1$d دقيقتان + دقيقة واحدة + دقيقتان %1$d دقائق %1$d دقيقة %1$d دقيقة @@ -1909,22 +1989,22 @@ %1$d ساعة %1$d ساعة %1$d يوم - %1$d يوم - %1$d يومان + يوم واحد + يومان %1$d أيام - %1$d يوم + %1$d يومًا %1$d يوم %1$d أسبوع أسبوع واحد أسبوعان %1$d أسابيع - %1$d أسبوع + %1$d أسبوعًا %1$d أسبوع %1$d شهر شهر واحد - شهران اثنان + شهران %1$d أشهر - %1$d شهر + %1$d شهرًا %1$d شهر %1$d سنة سنة واحدة @@ -1935,32 +2015,32 @@ %1$d مستخدم مستخدم واحد مستخدمان - %1$d مستخدمون - %1$d مستخدم + %1$d مستخدمين + %1$d مستخدمًا %1$d مستخدم %1$d مرات - %1$d مرة - %1$d مرة - %1$d مرة + مرة واحدة + مرتان + %1$d مرات %1$d مرة %1$d مرة - %1$d أمتار - %1$d متر - %1$d متر - %1$d متر - %1$d متر + %1$d متر + متر واحد + متران + %1$d أمتار + %1$d مترًا %1$d متر %1$d ملصقات - %1$d ملصق - %1$d ملصق + ملصق واحد + ملصقان اثنان %1$d ملصقات - %1$d ملصق + %1$d ملصقًا %1$d ملصق لا يوجد مشتركين مشترك واحد مشتركان - %1$d مشتركون - %1$d مشترك + %1$d مشتركين + %1$d مشتركًا %1$d مشترك %1$d %1$d @@ -2000,89 +2080,89 @@ **%1$d** يوم %1$d رسالة معاد توجيهها - رسالة معاد توجيهها - رسالتين معاد توجيههما + رسالة واحدة معاد توجيهها + رسالتان معاد توجيههما %1$d رسائل معاد توجيهها %1$d رسالة معاد توجيهها %1$d رسالة معاد توجيهها %1$d صورة صورة واحدة - صورتين + صورتان %1$d صور %1$d صورة %1$d صورة %1$d ملف ملف واحد - ملفين اثنين + ملفان اثنان %1$d ملفات - %1$d ملف + %1$d ملفًا %1$d ملف - صفر + %1$d ملف ملف واحد ملفان %1$d ملفات - %1$d ملف + %1$d ملفًا %1$d ملف %1$d ملف معاد توجيهه - ملف معاد توجيهه + ملف واحد معاد توجيهه ملفان معاد توجيههما %1$d ملفات معاد توجيهها - %1$d ملف معاد توجيهه + %1$d ملفًا معاد توجيهها %1$d ملف معاد توجيهه %1$d صورة معاد توجيهها - صورة معاد توجيهها - صورتين معاد توجيههما + صورة واحدة معاد توجيهها + صورتان معاد توجيههما %1$d صور معاد توجيهها %1$d صورة معاد توجيهها %1$d صورة معاد توجيهها %1$d مقطع مرئي معاد توجيهه - مقطع مرئي معاد توجيهه - مقطعين مرئيين معاد توجيههما - %1$d مقطع مرئي معاد توجيهه - %1$d مقاطع مرئية معاد توجيهها + مقطع مرئي واحد معاد توجيهه + مقطعان مرئيان معاد توجيههما + %1$d مقاطع مرئية معاد توجيهها + %1$d مقطعًا مرئيًا معاد توجيهها %1$d مقاطع مرئية معاد توجيهها - %1$d مقاطع صوتية معاد توجيهها - مقطع صوتي معاد توجيهه - مقطعين صوتيين معاد توجيههما - %1$d مقاطع صوتية معاد توجيهها - %1$d مقطع صوتية معاد توجيهه - %1$d مقطع صوتي معاد توجيهه + %1$d مسار معاد توجيهه + مسار واحد معاد توجيهه + مساران معاد توجيههما + %1$d مسارات معاد توجيهها + %1$d مسارًا معاد توجيهه + %1$d مسار معاد توجيهه %1$d رسالة صوتية معاد توجيهها - رسالة صوتية معاد توجيهها - رسالتان صوتيتان معاد توجيهها + رسالة صوتية واحدة معاد توجيهها + رسالتان صوتيتان معاد توجيههما %1$d رسائل صوتية معاد توجيهها %1$d رسالة صوتية معاد توجيهها %1$d رسالة صوتية معاد توجيهها %1$d رسالة مرئية معاد توجيهها رسالة مرئية معاد توجيهها - رسالتين مرئيتين معاد توجيههما + رسالتان مرئيتان معاد توجيههما %1$d رسائل مرئية معاد توجيهها %1$d رسالة مرئية معاد توجيهها %1$d رسالة مرئية معاد توجيهها %1$d موقع معاد توجيهه - موقع معاد توجيهه - موقعين معاد توجيههما + موقع واحد معاد توجيهه + موقعان معاد توجيههما %1$d مواقع معاد توجيهها - %1$d موقع معاد توجيهه + %1$d موقعًا معاد توجيهها %1$d موقع معاد توجيهه %1$d جهة اتصال معاد توجيهها - جهة اتصال معاد توجيهها - جهتين اتصال معاد توجيههما + جهة اتصال واحدة معاد توجيهها + جهتا اتصال معاد توجيههما %1$d جهات اتصال معاد توجيهها %1$d جهة اتصال معاد توجيهها %1$d جهة اتصال معاد توجيهها %1$d ملصق معاد توجيهها - ملصق معاد توجيهه - ملصقين معاد توجيههما + ملصق واحد معاد توجيهه + ملصقان معاد توجيههما %1$d ملصقات معاد توجيهها - %1$d ملصق معاد توجيهه + %1$d ملصقًا معاد توجيهها %1$d ملصق معاد توجيهه - و %1$d غيرهم - و %1$d غيره - و %1$d غيرهم - و %1$d غيرهم - و %1$d غيرهم - و %1$d غيرهم + و%1$d آخرون + وواحد آخر + واثنان آخران + و%1$d آخرون + و%1$d آخرون + و%1$d آخرون MMM dd yyyy, h:mm a MMM dd yyyy, HH:mm diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 96269bf2d..e164a9776 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -962,6 +962,8 @@ Einige Geräte besitzen ein kleines Licht, welches farbig leuchten oder blinken kann, um dich über neue Nachrichten zu informieren. Mitteilungen höherer Priorität funktionieren auch, wenn sich dein Telefon im \"Bitte nicht stören\"-Modus befindet. Allgemein + Stumm + Benachrichtigungen An Aus Standard (Ein) @@ -1051,6 +1053,9 @@ Standard Standard Schlaue Benachrichtigungen + Ausnahmen + Deine angepassten Benachrichtigungen werden in diesem Bereich angezeigt.\n\nUm Benachrichtigungen anzupassen, Chat mit dem Gesprächspartner öffnen, Profilbild antippen, dann \'Mitteilungen\' und \'Anpassen\'. + Keine %1$d / %2$s Deaktiviert Anzahl Benachrichtigungen @@ -1117,6 +1122,7 @@ Streaming Videos und Audios streamen Einige Videos können nicht gestreamt werden - z.B. alle Videos, die von Telegram für Android 4.7 und früher gesendet wurden. + Antippen, um Nummer zu ändern Lokale Datenbank Textnachrichten-Cache leeren? @@ -1145,13 +1151,25 @@ Mit Telegram Passport kannst du dich ganz einfach bei Webseiten und Diensten anmelden, die eine Identitätsprüfung erfordern.\n\nDeine Informationen, persönlichen Daten und Dokumente sind durch Ende-zu-Ende-Verschlüsselung geschützt. Niemand, einschließlich Telegram, kann ohne deine Erlaubnis darauf zugreifen.\n\nMehr dazu in unseren FAQs. Bitte Kennwort einrichten, um deine persönlichen Daten mit Ende-zu-Ende-Verschlüsselung zu schützen.\n\nDas Kennwort wird außerdem benötigt, wenn du dich mit Telegram von einem neuen Gerät verbindest. EIN KENNWORT ERSTELLEN - Reisepass löschen + Telegram Passport löschen Möchtest du wirklich deinen Telegram Passport löschen? Bitte nur lateinische Schriftzeichen benutzen. + In diesem Bereich kannst du Scans einer beglaubigter Übersetzung deines Reisepasses hochladen. + Scans beglaubigter Übersetzung deines nationalen Reisepasses hochladen. + In diesem Bereich kannst du Scans einer beglaubigten Übersetzung deines Führerscheins hochladen. + Scans beglaubigter Übersetzung deines Personalausweises hochladen. Scan deiner Versorgerrechnung hochladen. Scan deines Kontoauszugs hochladen. Scan deines Mietvertrages hochladen + Scan deiner Reisepass-Registrierung hochladen. + Scan deiner temporären Registrierung hochladen. Um deine Adresse zu bestätigen, Scan oder ein Bild der ausgewählten Dokumente (alle Seiten) hochladen. + In diesem Bereich kannst du Scans einer beglaubigten Übersetzung deines Versorgerrechnung hochladen. + In diesem Bereich kannst du Scans einer beglaubigten Übersetzung deines Kontoauszuges hochladen. + Scans beglaubigter Übersetzung deines Mietvertrags hochladen. + In diesem Bereich kannst du Scans einer beglaubigten Übersetzung deiner Reisepass-Registrierung hochladen. + Scans beglaubigter Übersetzung deiner vorläufigen Registrierung hochladen. + Bitte Scans beglaubigter Übersetzung des ausgewählten Dokumentes hochladen. Versorgerrechnung hinzufügen Kontoauszug hinzufügen Mietvertrag hinzufügen @@ -1181,7 +1199,7 @@ Code Bitte den Code eintippen, der dir gerade an %1$s gesendet wurde. Bitte dein Telegram-Kennwort eingeben, damit du auf deine persönlichen Daten zugreifen kannst. - %1$s verlangt Zugriff auf deine persönlichen Daten, damit du dich dort registrieren kannst. + **%1$s** verlangt Zugriff auf deine persönlichen Daten, damit du dich dort registrieren kannst. Dein Kennwort wird benötigt, um die Daten zu entschlüsseln. Du akzeptierst die *%1$s Datenschutzerklärung* und erlaubst %2$s dir Nachrichten zu senden. Du sendest deine Dokumente direkt %1$s und erlaubst dem %2$s Bot, dir Nachrichten zu senden. @@ -1189,21 +1207,31 @@ Reisepass hinzufügen Nationalen Reisepass hinzufügen Reisepass-Registrierung - Scan deiner Reisepass-Registrierung hochladen. Vorläufige Registrierung - Scan deiner temporären Registrierung hochladen. Personalausweis hinzufügen Führerschein hinzufügen Persönliche Daten Deine persönlichen Daten eingeben Identitätsdokument Scan deines Ausweises hochladen + Scan deines Reisepasses hochladen + Scan deines nationalen Reisepasses hochladen + Scan deines Personalausweises hochladen + Scan deines Führerscheins hochladen Persönliche Daten + Angaben zum Dokument Vorname + Zwischenname + Nachname + Name (Latein) + Zwischenname (Latein) + Nachname (Latein) + Name (%1$s) + Zwischenname (%1$s) + Nachname (%1$s) Geschlecht auswählen Männlich Weiblich - Nachname Geburtsdatum Geschlecht Ausweisnummer @@ -1212,7 +1240,8 @@ Wohnsitz Selfie Notwendige Dokumente - Selfie von dir zusammen mit einem Dokument hochladen + Selfie von dir mit dem Dokument hochladen + Übersetzung Vorderseite Foto der Vorderseite des Dokuments hochladen Rückseite @@ -1247,7 +1276,58 @@ Dokument hinzufügen Du hast noch keine Dokumente Du kannst deine Telefonnummer, E-Mail-Adresse, Identitätsdokument oder Wohnadresse hinzufügen. - Antippen, um Fehler zu korrigieren. + Antippen zum Korrigieren. + %1$s oder %2$s + Dein Name + Dein Name auf %1$s + Dein Name in der Sprache des Landes (%1$s), welches dein Dokument ausgestellt hat. + Bitte überprüfe, ob dieser Name stimmt:\n\n%1$s %2$s %3$s + Arabisch + Aserbaidschanisch + Bulgarisch + Bengalisch + Tschechisch + Dänisch + Deutsch + Dhivehi + Dzongkha + Griechisch + Spanisch + Estnisch + Persisch + Französisch + Hebräisch + Kroatisch + Ungarisch + Armenisch + Indonesisch + Isländisch + Italienisch + Japanisch + Georgisch + Khmer + Koreanisch + Laotisch + Litauisch + Lettisch + Mazedonisch + Mongolisch + Malaiisch + Birmanisch + Nepalesisch + Niederländisch + Polnisch + Portugiesisch + Rumänisch + Russisch + Slowakisch + Slowenisch + Thailändisch + Turkmenisch + Türkisch + Ukrainisch + Usbekisch + Vietnamesisch Sitzungen Aktuelle Sitzung @@ -1735,13 +1815,13 @@ Kostenlos Sicher Leistungsstark - Cloud-Basiert + Cloud-basiert Die **schnellste** Messaging App der Welt.\n**Kostenlos** und **sicher**. **Telegram** übermittelt Nachrichten\nschneller als jede andere Anwendung. **Telegram** bleibt immer gratis.\nKeine Werbung. Keine Abo-Gebühren. **Telegram** schützt deine Nachrichten\nvor Hacker-Angriffen. **Telegram** hat keine Begrenzungen auf\ndie Größe deiner Medien oder Chats. - **Telegram** kannst du vom Handy\nTablet oder auch Computer\nsynchronisiert benutzen. + **Telegram** kannst du vom Handy,\nTablet oder auch Computer\nsynchronisiert benutzen. JETZT BEGINNEN Kontoeinstellungen diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index b6d9a0fe2..cf6a9171d 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -457,7 +457,7 @@ El archivo no debe superar los %1$s Almacenamiento no montado Transferencia USB activa - Almacenamiento Interno + Almacenamiento interno Almacenamiento Externo Raíz del Sistema Tarjeta SD @@ -560,7 +560,7 @@ Escribe un comentario... Toca y ve los GIF guardados Anclar - Notificar a los miembros + Notificar a todos los miembros Desanclar ¿Quieres anclar este mensaje en el grupo? ¿Quieres anclar este mensaje en el canal? @@ -940,7 +940,7 @@ Vista previa en la app Restablecer Restablecer las notificaciones - Deshacer las notificaciones personalizadas para todos tus usuarios y grupos + Deshacer las notificaciones personalizadas para todos tus contactos y grupos Notificaciones y sonidos Notificaciones personalizadas Notificaciones emergentes @@ -962,10 +962,12 @@ LED es una pequeña luz que parpadea en algunos dispositivos para señalar los mensajes nuevos. Las notificaciones con prioridad alta funcionarán aunque tu teléfono esté en modo no molestar. General - Activadas - Desactivadas - Por defecto (Activadas) - Por defecto (Apagadas) + Silenciado + No silenciado + + No + Por defecto (Sí) + Por defecto (No) Activar Desactivar Usuarios bloqueados @@ -982,7 +984,7 @@ Mensajes anclados Idioma Personalizado - Por favor, considera que el soporte de Telegram está en manos de voluntarios. Respondemos lo antes posible, pero puede tomar tiempo.\n\nPor favor, mira las preguntas frecuentes de Telegram]]>: tienen respuestas para la mayoría de las preguntas y soluciones a problemas]]>. + Por favor, considera que el soporte de Telegram está hecho por voluntarios. Respondemos lo antes posible, pero puede tomar tiempo.\n\nPor favor, mira las Preguntas frecuentes de Telegram]]>: tienen respuestas para la mayoría de las preguntas y soluciones a problemas]]>. Preguntar Preguntas frecuentes Preguntas frecuentes @@ -1046,11 +1048,14 @@ Activadas Desactivadas Desactivado - Apagado + No Sonidos en el chat Por defecto Por defecto Notificaciones inteligentes + Excepciones + Aquí aparecerán los chats que no tengan los ajustes por defecto para las notificaciones.\n\nPuedes personalizar las notificaciones para un chat abriendo su información y seleccionando “Notificaciones”. + Ninguna %1$d / %2$s Desactivadas Frecuencia de alertas @@ -1117,6 +1122,7 @@ Streaming Streaming de vídeo y audio Algunos vídeos no se pueden reproducir en streaming. Por ejemplo, todos los vídeos que fueron enviados desde Android usando Telegram 4.7 y versiones anteriores. + Toca para cambiar el número de teléfono Base de datos local ¿Eliminar los mensajes en la caché? @@ -1142,19 +1148,31 @@ Información solicitada Información entregada ¿Qué es Telegram Passport? - Con Telegram Passport puedes registrarte fácilmente en sitios web y servicios que requieren una identificación.\n\nTu información, datos personales y documentos están protegidos con cifrado end-to-end. Nadie, incluyendo a Telegram, puede acceder a ellos sin tu permiso.\n\nPuedes visitar nuestras preguntas frecuentes para conocer más. + Con Telegram Passport puedes registrarte fácilmente en sitios web y servicios que requieren una identificación.\n\nTu información, datos personales y documentos están protegidos con cifrado end-to-end. Nadie, incluyendo a Telegram, puede acceder a ellos sin tu permiso.\n\nPuedes visitar nuestras Preguntas frecuentes para conocer más. Por favor, crea una contraseña para asegurar tus datos personales con cifrado end-to-end.\n\nEsta contraseña también será requerida cuando inicies sesión en Telegram en un nuevo dispositivo. CREAR UNA CONTRASEÑA - Eliminar pasaporte + Eliminar Telegram Passport ¿Quieres eliminar tu Telegram Passport? Por favor, usa sólo caracteres latinos. + Subir escaneos de traducciones verificadas de tu pasaporte. + Subir escaneos de traducciones verificadas de tu pasaporte interno. + Subir escaneos de traducciones verificadas de tu licencia de conducir. + Subir escaneos de traducciones verificadas de tu tarjeta de identificación. Subir un escaneo de tu factura de servicios. Subir un escaneo de tu extracto de cuenta bancaria. - Subir un escaneo de tu contrato de arrendamiento. + Subir un escaneo de tu contrato de alquiler. + Subir un escaneo de la página de tu registro del pasaporte. + Subir un escaneo de tu registro temporal. Para confirmar tu dirección, por favor, sube un escaneo o foto del documento seleccionado (todas las páginas). + Subir escaneos de traducciones verificadas de tu factura de servicios. + Subir escaneos de traducciones verificadas de tu extracto de cuenta. + Subir escaneos de traducciones verificadas de tu contrato de arrentamiento. + Subir escaneos de traducciones verificadas de la página de registro de tu pasaporte. + Subir escaneos de traducciones verificadas de tu registro temporal. + Por favor, sube escaneos de traducciones verificadas de los documentos seleccionados. Añadir factura de servicios Añadir extracto de cuenta - Añadir contrato de arrendamiento + Añadir contrato de alquiler Dirección Dirección de residencia Por favor, pon tu dirección @@ -1181,29 +1199,39 @@ Código Por favor, pon el código que hemos enviado a %1$s. Por favor, pon tu contraseña para acceder a tus datos personales. - %1$s solicita acceso a tus datos personales para registrarte para sus servicios. + **%1$s** solicita acceso a tus datos personales para registrarte en sus servicios. Por favor, pon tu contraseña de Telegram para descifrar tus datos. Aceptas la *política de privacidad de %1$s* y permites que @%2$s te envíe mensajes. Estás enviando documentos directamente a %1$s y permitiendo que @%2$s te envíe mensajes. AUTORIZAR Añadir pasaporte Añadir pasaporte interno - Añadir registro de pasaporte - Subir un escaneo de la página de tu registro del pasaporte. + Registro de pasaporte Registro temporal - Subir un escaneo de tu registro temporal. Añadir tarjeta de identificación Añadir licencia de conducir Datos personales Completa tus datos personales - Tarjeta de identificación + Documento de identidad Sube un escaneo de tu pasaporte u otra ID + Subir un escaneo de tu pasaporte + Subir un escaneo de tu pasaporte interno + Subir un escaneo de tu tarjeta de identificación + Subir un escaneo de tu licencia de conducir Datos personales + Datos del documento Nombre + Segundo nombre + Apellidos + Nombre (latino) + Segundo nombre (latino) + Apellidos (latino) + Nombre (%1$s) + Segundo nombre (%1$s) + Apellidos (%1$s) Elegir género Masculino Femenino - Apellidos Nacimiento Género Número de documento @@ -1213,6 +1241,7 @@ Selfie Documentos necesarios Sube una selfie tuya sosteniendo el documento + Traducción Lado delantero Sube una foto del lado delantero del documento Reverso @@ -1240,14 +1269,65 @@ ¿Eliminar escaneo? Subir escaneos Subir escaneos adicionales - No puedes subir más de %1$s archivos. + No puedes subir más de %1$s. Puedes subir sólo archivos de imagen. Escanea tu pasaporte Escanea tu pasaporte o tarjeta de identificación con la zona legible para máquinas para completar los datos personales automáticamente. Añadir un documento No tienes documentos aún - Puedes añadir un número de teléfono, dirección de correo, tarjeta de identificación o dirección residencial. + Puedes añadir un número de teléfono, dirección de correo, documento de identificación o dirección residencial. Toca para corregir errores. + %1$s o %2$s + Tu nombre + Tu nombre en %1$s + Tu nombre en el idioma del país (%1$s) en el que fue emitido el documento. + Por favor, revisa si este nombre es correcto:\n\n%1$s %2$s %3$s + árabe + azerbaiyano + búlgaro + bengalí + checo + danés + alemán + maldivo + butanés + griego + español + estonio + persa + francés + hebreo + croata + húngaro + armenio + indonesio + islandés + italiano + japonés + georgiano + camboyano + coreano + lao + lituano + letón + macedonio + mongol + malayo + birmano + nepalí + holandés + polaco + portugués + rumano + ruso + eslovaco + esloveno + tailandés + turcomano + turco + ucraniano + uzbeko + vietnamita Sesiones activas Sesión actual @@ -1386,7 +1466,7 @@ ROJO VERDE AZUL - Apagado + No Lineal Radial ¿Quieres eliminar esta foto? @@ -1599,10 +1679,10 @@ Eliminaste a un2 Dejaste el grupo Añadiste a un2 - Conseguiste %1$s - un1 consiguió %1$s - Conseguiste %1$s en un2 - un1 consiguió %1$s en un2 + Has conseguido %1$s + un1 ha conseguido %1$s + Has conseguido %1$s en un2 + un1 ha conseguido %1$s en un2 Eliminaste la foto del grupo Cambiaste la foto del grupo Cambiaste el nombre del grupo a un2 @@ -1624,10 +1704,10 @@ Tarjeta de identificación Factura de servicios Extracto de cuenta - Contrato de arrendamiento + Contrato de alquiler Número de teléfono Dirección de correo - Tu versión de Telegram no soporta este mensaje. Por favor, actualiza tu app para verlo: https://telegram.org/update + Tu versión de Telegram no es compatible con este mensaje. Por favor, actualiza tu app para verlo: https://telegram.org/update Foto Vídeo Foto con autodestrucción @@ -1786,7 +1866,7 @@ %1$s (%2$s) Aún no has realizado llamadas. La app de **%1$s** está usando un protocolo incompatible. Necesita actualizar la app para poder llamar. - La app de **%1$s** no soporta llamadas. Necesita actualizar la app para poder llamar. + La app de **%1$s** no es compatible con las llamadas. Necesita actualizar la app para poder llamar. Por favor, evalúa la calidad de tu llamada de Telegram Telegram necesita acceso a tu micrófono para poder realizar llamadas. Añade un comentario opcional diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 7fb92f90e..1ede35e0a 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -804,7 +804,7 @@ Blocca Modifica Elimina - Home + Casa Cellulare Lavoro Altro @@ -962,16 +962,18 @@ Il led è una piccola luce lampeggiante usata in alcuni dispositivi per indicare nuovi messaggi. Le notifiche con priorità più alta funzioneranno anche se il telefono è in modalità Non disturbare. Generali + Silenziato + Non silenziato No - Predefinite (On) - Predefinite (Off) + Default (On) + Default (Off) Attiva Disattiva Utenti bloccati Esci Nessun suono - Predefinito + Default Assistenza Solo se silenzioso Sfondo chat @@ -1048,9 +1050,12 @@ Disattivato No Suoni in-chat - Predefinito - Predefinita + Default + Default Notifiche intelligenti + Eccezioni + Questa sezione mostrerà tutte le chat con impostazioni di notifica non predefinite.\n\nPuoi personalizzare le notifiche per una chat aprendo il suo profilo e scegliendo \'Notifiche\'. + Nessuna %1$d / %2$s Disattivate Frequenza avviso sonoro @@ -1117,6 +1122,7 @@ Streaming Streaming file video e audio Alcuni video non possono essere riprodotti in streaming – ad esempio, tutti i video inviati da Android usando Telegram 4.7 o precedente. + Tocca per cambiare numero di telefono Database locale Cancellare i messaggi salvati nella cache? @@ -1145,13 +1151,25 @@ Con Telegram Passport puoi iscriverti facilmente ai siti web e ai servizi che richiedono la verifica dell\'identità.\n\nLe tue informazioni, i tuoi dati personali e i tuoi documenti sono protetti da crittografia end-to-end. Nessuno, incluso Telegram, può accedervi senza il tuo permesso.\n\nPuoi visitare le nostre FAQ per saperne di più. Per favore crea una password per rendere sicuri i tuoi dati personali tramite crittografia end-to-end.\n\nQuesta password sarà inoltre richiesta ogni volta che accedi a Telegram su un nuovo dispositivo. CREA UNA PASSWORD - Elimina passaporto + Elimina Telegram Passport Sei sicuro di voler cancellare il tuo Telegram Passport? Usare solo caratteri latini. + Carica le scansioni di una traduzione verificata del tuo passaporto. + Carica le scansioni di una traduzione verificata del tuo passaporto nazionale. + Carica le scansioni di una traduzione verificata della tua patente. + Carica le scansioni di una traduzione verificata della tua carta d\'identità. Carica una scansione della tua bolletta. Carica una scansione del tuo estratto conto. Carica una scansione del tuo contratto di locazione. + Carica una scansione della pagina di registrazione del tuo passaporto. + Carica una scansione della tua registrazione temporanea. Per confermare il tuo indirizzo, carica una scansione o una foto del documento selezionato (tutte le pagine). + Carica le scansioni di una traduzione verificata della tua bolletta. + Carica le scansioni di una traduzione verificata del tuo estratto conto. + Carica le scansioni di una traduzione verificata del tuo contratto di locazione. + Carica le scansioni di una traduzione verificata della pagina di registrazione del passaporto. + Carica le scansioni di una traduzione verificata della tua registrazione temporanea. + Per favore carica le scansioni di una traduzione verificata del documento selezionato. Aggiungi bolletta Aggiungi estratto conto Aggiungi contratto di locazione @@ -1189,21 +1207,31 @@ Aggiungi passaporto Aggiungi passaporto nazionale Registrazione passaporto - Carica una scansione della pagina di registrazione del tuo passaporto. Registrazione temporanea - Carica una scansione della tua registrazione temporanea. Aggiungi carta d\'identità Aggiungi patente di guida Dettagli personali Inserisci i tuoi dettagli personali Documento d\'identità Carica una scansione del tuo passaporto o di un altro documento + Carica una scansione del tuo passaporto + Carica una scansione del tuo passaporto nazionale + Carica una scansione della tua carta d\'identità + Carica una scansione della tua patente Dettagli personali + Dettagli documento Nome + Secondo nome + Cognome + Nome (latino) + Secondo nome (latino) + Cognome (latino) + Nome (%1$s) + Secondo nome (%1$s) + Cognome (%1$s) Seleziona genere Uomo Donna - Cognome Data di nascita Genere Numero documento @@ -1213,6 +1241,7 @@ Selfie Documenti richiesti Carica un tuo selfie mentre reggi il documento. + Traduzione Lato frontale Carica una foto del lato frontale del documento Lato posteriore @@ -1248,6 +1277,57 @@ Non hai ancora alcun documento Puoi aggiungere il tuo numero di telefono, indirizzo email, documento d\'identità o indirizzo di residenza. Tocca per correggere gli errori. + %1$s o %2$s + Il tuo nome + Il tuo nome in %1$s + Il tuo nome nella lingua del Paese (%1$s) che ha emesso il documento. + Per favore controlla se questo nome è corretto:\n\n%1$s %2$s %3$s + Arabo + Azero + Bulgaro + Bangla + Ceco + Danese + Tedesco + Divehi + Dzongkha + Greco + Spagnolo + Estone + Persiano + Francese + Ebraico + Croato + Ungherese + Armeno + Indonesiano + Islandese + Italiano + Giapponese + Georgiano + Khmer + Coreano + Lao + Lituano + Lettone + Macedone + Mongolo + Malese + Birmano + Nepali + Olandese + Polacco + Portoghese + Rumeno + Russo + Slovacco + Sloveno + Tailandese + Turkmeno + Turco + Ucraino + Uzbeko + Vietnamita Sessioni attive Sessione attuale @@ -1792,7 +1872,7 @@ Aggiungi un commento opzionale Richiama Richiama - Predefinita + Default Sei sicuro di voler eliminare questa voce dal registro delle chiamate? Chiamata Telegram Auricolare diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 992e57e33..f7e55f033 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -23,8 +23,8 @@ 기기에 있는 연락처가 계정에 추가되었습니다. 휴대폰 인증 - 인증 코드가 담긴 SMS를 **%1$s**(으)로 보냈습니다. - 회원님 기기에 설치된 **Telegram**앱으로 코드를 전송했습니다. + **%1$s** 번호로 인증 코드가 담긴 SMS츨 보냈습니다. + 회원님의 다른 기기에 설치된 **텔레그램** 앱으로 코드를 보냈습니다. **%1$s** 번호로 인증 전화를 걸었습니다. \n\n전화를 받지 마세요. 텔레그램이 모든 것을 자동으로 처리합니다. 코드를 말해 드리기 위해 **%1$s** 번호로 전화를 걸고 있습니다. 텔레그램이 %1$d:%2$02d 뒤에는 전화를 걸 것입니다 @@ -211,15 +211,15 @@ un1 님이 실시간 위치를 고정했습니다 un1 님이 GIF를 고정했습니다 un1 님이 트랙을 고정했습니다 - 이 그룹이 슈퍼그룹으로 업그레이드됐습니다 + 그룹이 슈퍼그룹으로 업그레이드되었습니다 %1$s 그룹이 슈퍼그룹으로 업그레이드됐습니다 블랙리스트에 적힌 사용자는 그룹에서 추방되며, 관리자가 초대해야만 다시 들어올 수 있습니다. 이 사용자에게는 초대 링크도 작동하지 않습니다. 블랙리스트에 적힌 사용자는 그룹에서 추방되며, 관리자가 초대해야만 다시 들어올 수 있습니다. 이 사용자에게는 초대 링크도 작동하지 않습니다. 채널 만들기 채널명 채널에 연락 상대 추가 - 사람들이 위 링크를 공유하며 텔레그램 검색으로 회원님의 채널을 찾을 수 있습니다. - 사람들이 위 링크를 공유하며 텔레그램 검색으로 회원님의 그룹을 찾을 수 있습니다. + 사람들이 위 링크를 공유하거나 텔레그램 검색을 이용하여 채널을 찾을 수 있습니다. + 사람들이 위 링크를 공유하거나 텔레그램 검색을 이용하여 그룹을 찾을 수 있습니다. 링크 사람들이 위 링크를 통해 회원님의 채널에 들어올 수 있습니다. 링크는 언제든지 폐기하실 수 있습니다. 사람들이 위 링크를 통해 회원님의 그룹에 들어올 수 있습니다. 링크는 언제든지 폐기하실 수 있습니다. @@ -619,12 +619,12 @@ 읽지 않은 메시지 스티커 묶음 검색 URL - Map Preview Provider - Choose Map Preview Provider - Telegram + 지도 미리보기 제공 기관 + 지도 미리보기 제공 기관을 선택하세요 + 텔레그램 Google Yandex - Nobody + 없음 %1$s 님이 자동 삭제 타이머를 %2$s(으)로 설정했습니다 자동 삭제 타이머를 %1$s(으)로 설정하셨습니다 @@ -962,10 +962,12 @@ LED는 일부 기기에서 새로운 메시지를 받았음을 나타내는 반짝이는 작은 빛입니다. 우선순위가 높은 알림은 휴대폰이 방해 금지 상태이더라도 작동합니다. 일반 - 켜기 - 끄기 + 음소거됨 + Unmuted + 켜짐 + 꺼짐 기본 (켬) - 기본 (끔) + 기본 (꺼짐) 켜기 끄기 차단 목록 @@ -1051,6 +1053,9 @@ 기본 기본 스마트 알림 + Exceptions + This section will list all chats with non-default notification settings.\n\nYou can customize notifications for a chat by opening its profile and choosing \'Notifications\'. + 없음 %1$d / %2$s 사용 안 함 소리 알림 간격 @@ -1099,7 +1104,7 @@ 프록시 협찬 이 채널은 회원님의 프록시 서버로 인해 나타났습니다. 채널을 대화방 목록에서 제거하려면, 텔레그램 설정에서 프록시를 비활성화하세요. SOCKS5 프록시 설정입니다. - MTProto 프록시 설정. + MTProto 프록시 설정입니다. 이 프록시를 사용하시면 대화방 목록에 협찬 채널이 표시될 수 있습니다. 이는 회원님의 텔레그램 트래픽을 공개하지 않습니다. 전화에 프록시 사용 프록시 서버는 통화 품질을 저하시킬 수 있습니다. @@ -1117,6 +1122,7 @@ 스트리밍 동영상 및 음악 파일 스트리밍 어떤 동영상은 스트리밍할 수 없습니다 – 예로, 안드로이드에서 텔레그램 4.7 이하 버전으로 보낸 동영상은 모두 스트리밍할 수 없습니다. + Tap to change phone number 로컬 데이터베이스 캐시가 된 문자 메시지를 비울까요? @@ -1145,13 +1151,25 @@ 텔레그램 패스포트와 함께라면 본인 확인이 필요한 웹사이트와 서비스에 손쉽게 가입하실 수 있습니다.\n\n회원님의 정보와 개인 데이터, 서류는 단대단 암호화로 보호됩니다. 텔레그램을 포함하여, 누구도 회원님의 승인 없이 이들에 접속할 수 없습니다.\n\nFAQ를 방문하여 더 많은 정보를 얻으실 수 있습니다. Please create a password to secure your personal data with end-to-end encryption.\n\nThis password will also be required whenever you log in to Telegram on a new device. 비밀번호를 만드세요 - 패스포트 삭제 + 텔레그램 패스포트 삭제 정말 텔레그램 패스포트를 삭제하시겠습니까? 로마자만 사용해 주세요. + Upload scans of verified translation of your passport. + Upload scans of verified translation of your internal passport. + Upload scans of verified translation of your driver licence. + Upload scans of verified translation of your identity card. 회원님의 공공 요금 고지서를 스캔하여 올리세요. 회원님의 입출금 내역서를 스캔하여 올리세요. 회원님의 임차 계약서를 스캔하여 올리세요. + 여권 등록 페이지를 스캔하여 올리세요. + 회원님의 가등기를 스캔하여 올리세요 회원님의 주소를 확인하기 위함이오니, 선택된 서류(모든 쪽)의 사진이나 스캔을 올려 주세요 + Upload scans of verified translation of your utility bill. + Upload scans of verified translation of your bank statement. + Upload scans of verified translation of your tenancy agreement. + Upload scans of verified translation of your passport registration page. + Upload scans of verified translation of your temporary registration. + Please upload scans of verified translation of the selected document. 공공 요금 고지서 추가 입출금 내역서 추가 임차 계약서 추가 @@ -1181,29 +1199,39 @@ 코드 방금 %1$s(으)로 받은 인증 코드를 입력해 주세요. 개인 데이터에 접근하려면 비밀번호를 입력해 주세요. - %1$s requests access to your personal data to sign you up for their services. + **%1$s** requests access to your personal data to sign you up for their services. 데이터를 해독하려면 텔레그램 비밀번호를 입력해 주세요. - You accept the *%1$s Privacy Policy* and allow their @%2$s to send you messages. + *%1$s 개인 정보 정책*을 수락하시어 @%2$s 봇이 회원님에게 메시지를 보낼 수 있도록 합니다. You are sending your documents directly to %1$s and allowing their @%2$s to send you messages. 승인 여권 추가 내부 여권 추가 여권 등록 - 여권 등록 페이지를 스캔하여 올리세요. 가등기 - 회원님의 가등기를 스캔하여 올리세요 신분증 추가 운전 면허증 추가 개인 신상 명세 개인 신상 명세를 채우세요 신분 증명서 회원님의 여권이나 다른 신분증을 스캔하여 올리세요 + Upload a scan of your passport + Upload a scan of your internal passport + Upload a scan of your identity card + Upload a scan of your driver\'s license 개인 신상 명세 + Document Details 성명 + Middle name + + Name (latin) + Middle name (latin) + Last name (latin) + Name (%1$s) + Middle name (%1$s) + Last name (%1$s) 성별을 선택하세요 남성 여성 - 생년월일 성별 서류 번호 @@ -1213,6 +1241,7 @@ 셀카 필요한 서류 서류를 든 본인의 모습을 셀카 찍어 올리세요 + Translation 앞면 서류의 앞면을 사진 찍어 올리세요 반대면 @@ -1248,6 +1277,57 @@ 아직 서류가 없습니다 회원님의 전화번호나 이메일 주소, 신분 증명서, 거주지 주소를 추가하실 수 있습니다. 짧게 눌러 오류를 바로잡으세요 + %1$s or %2$s + Your name + Your name in %1$s + Your name in the language of the country (%1$s) that issued the document. + Please check if this name is correct:\n\n%1$s %2$s %3$s + Arabic + Azerbaijani + Bulgarian + Bangla + Czech + Danish + German + Divehi + Dzongkha + Greek + Spanish + Estonian + Persian + French + Hebrew + Croatian + Hungarian + Armenian + Indonesian + Icelandic + Italian + Japanese + Georgian + Khmer + Korean + Lao + Lithuanian + Latvian + Macedonian + Mongolian + Malay + Burmese + Nepali + Dutch + Polish + Portuguese + Romanian + Russian + Slovak + Slovenian + Thai + Turkmen + Turkish + Ukrainian + Uzbek + Vietnamese 활성화된 세션 현재 세션 @@ -1293,7 +1373,7 @@ 지문인식에 실패했습니다. 다시 시도해주세요. 화면 캡처 허용 활성화할 시 앱 안에서 스크린샷을 찍으실 수 있으나, 암호가 설정된 때에도 주고받은 대화가 최근 실행한 앱 목록에서 보입니다.\n\n적용이 안 된다면 앱을 재시작하세요. - Too many tries.\nPlease try again in %1$s. + 너무 많이 시도하셨습니다.\n%1$s초 뒤에 다시 시도해 주세요. 파일 미디어 @@ -1308,7 +1388,7 @@ 이 대화방에 음악을 공유해두면 회원님의 모든 기기에서 접근하실 수 있습니다. 이 대화방에 파일과 문서를 공유해 두면 회원님의 모든 기기에서 접근하실 수 있습니다. 이 대화방에 링크를 공유해두면 회원님의 모든 기기에서 접근하실 수 있습니다. - Share voice messages in this chat and access them on any of your devices. + 이 대화방에 음성 메시지를 공유해 두어 어느 기기에서든 열람하세요. 이 대화방에서 공유된 사진과 동영상이 여기에 표시됩니다. 이 대화에서 공유된 음악이 여기에 표시됩니다. 이 대화에서 공유된 문서가 여기에 표시됩니다. @@ -1807,8 +1887,8 @@ 이 작업은 대화의 내용이 노출되지 않지만, 향 후 문제해결에 도움이 됩니다. 텔레그램 전화를 개선할 수 있도록 도와주셔서 감사합니다. %s(으)로서 수신 중 - 문구로 응답하기 - 이 빠른 응답은 회원님에게 텔레그램 메시지와 함께 전화가 걸려올 때 활성화됩니다. 무엇이든지 원하는 말로 바꾸세요. + 문자로 응답 + 이러한 빠른 응답 문자들로 전화가 걸려올 때 텔레그램 메시지를 보내어 응답하실 수 있습니다. 무엇이든지 원하는 말로 바꾸세요. 지금 대화할 수 없어요. 무슨 일이죠? 곧바로 전화할게요. 나중에 전화할게요. diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index f8b18087c..206a1c877 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -668,7 +668,7 @@ %1$s heeft een sticker gestuurd naar de groep %2$s %1$s heeft een %3$s sticker gestuurd naar de groep %2$s %1$s heeft je uitgenodigd voor de groep %2$s - %1$s heeft de groepsnam van %2$s gewijzigd + %1$s heeft de groepsnaam van %2$s gewijzigd %1$s heeft de groepsfoto voor %2$s aangepast %1$s heeft %3$s uitgenodigd voor de groep %2$s %1$s is terug in de groep %2$s @@ -962,6 +962,8 @@ Sommige apparaten hebben een LED-functie, om d.m.v. licht aan te geven dat er nieuwe berichten zijn. Meldingen met hoge prioriteit werken ook als je telefoon op \"Niet storen\" staat. Algemeen + Stil + Geluid aan Aan Uit Standaard (Aan) @@ -1051,6 +1053,9 @@ Standaard Standaard Slimme meldingen + Uitzonderingen + Hier vind je alle chats met niet-standaard berichtgevingsinstellingen.\n\nJe kunt de instellingen van een chat wijzigen door het profiel te openen en naar ‘Berichtgeving’ te gaan. + Geen %1$d / %2$s Uitgeschakeld Aantal geluidsmeldingen @@ -1117,6 +1122,7 @@ Streaming Muziek en audio streamen Sommige video\'s kunnen niet worden gestreamd, bijvoorbeeld video\'s verstuurd vanaf Android met Telegram versie 4.7 en ouder. + Tik om je nummer te wijzigen Lokale database Gecachet tekstberichten wissen? @@ -1145,13 +1151,25 @@ Met Telegram Passport kun je je makkelijk aanmelden voor websites en diensten die identiteitsverificatie vereisen.\n\nJe informatie, persoonsgegevens en documenten zijn beschermd middels end-to-end-versleuteling. Niemand heeft toegang tot deze gegevens zonder je toestemming, inclusief Telegram.\n\nJe kunt onze veelgestelde vragen bekijken voor meer informatie. Stel een wachtwoord in om je persoonsgegevens te beveiligen met end-to-end-versleuteling.\n\nDit wachtwoord heb je ook nodig wanneer je inlogt op Telegram vanaf een nieuw apparaat. Stel een wachtwoord in - Passport verwijderen + Telegram Passport verwijderen Telegram Passport echt verwijderen? Controleer of je naam geen ongeldige tekens bevat. + Upload scans van een geverifieerde vertaling van je paspoort. + Upload scans van een geverifieerde vertaling van je nationale paspoort. + Upload scans van een geverifieerde vertaling van je rijbewijs. + Upload scans van een geverifieerde vertaling van je identiteitsbewijs. Upload een scan van je energierekening Upload een scan van je bankafschrift Upload een scan van je huurovereenkomst + Upload een scan van je paspoortregistratiepagina + Upload een scan van je tijdelijke identiteitsbewijs Upload een scan of foto van het gekozen document (alle pagina\'s) om je adres te bevestigen. + Upload scans van een geverifieerde vertaling van je energierekening. + Upload scans van een geverifieerde vertaling van je bankafschrift. + Upload scans van een geverifieerde vertaling van je huurovereenkomst. + Upload scans van een geverifieerde vertaling van je paspoortregistratiepagina. + Upload scans van een geverifieerde vertaling van je tijdelijke identiteitsbewijs. + Upload scans van een geverifieerde vertaling van het gekozen document. Energierekening toevoegen Bankafschrift toevoegen Huurovereenkomst toevoegen @@ -1181,7 +1199,7 @@ Code Voer de bevestigingscode in die we hebben verstuurd naar %1$s. Voer je wachtwoord in voor toegang tot je persoonsgegevens - %1$s vraagt om toegang tot je persoonsgegevens om aan te melden de door hen aangeboden diensten + **%1$s ** vraagt om toegang tot je persoonsgegevens om je aan te melden voor de door hen aangeboden diensten Voer je Telegram-wachtwoord in om je gegevens te ontsleutelen. Je gaat akkoord met het *%1$s Privacybeleid* en staat toe dat \n@%2$s je berichten stuurt. Je stuurt je documenten direct naar %1$s en staat %2$s toe je berichten te sturen. @@ -1189,21 +1207,31 @@ Paspoort toevoegen Nationaal paspoort toevoegen Paspoortregistratie - Upload een scan van je paspoortregistratiepagina Tijdelijk identiteitsbewijs - Upload een scan van je tijdelijke identiteitsbewijs Identiteitskaart toevoegen Rijbewijs toevoegen Persoonsgegevens Voer je persoonsgegevens in Identiteitsbewijs Upload een scan van je paspoort of ander identiteitsbewijs + Upload een scan van je paspoort + Upload een scan van je nationaal paspoort + Upload een scan van je identiteitskaart + Upload een scan van je rijbewijs Persoonsgegevens + Documentdetails Naam + Tweede naam + Achternaam + Naam (Latijns alfabet) + Tweede naam (Latijns alfabet) + Achternaam (Latijns alfabet) + Naam (%1$s) + Tweede naam (%1$s) + Achternaam (%1$s) Kies je geslacht Man Vrouw - Achternaam Geboortedatum Geslacht Documentnummer @@ -1211,8 +1239,9 @@ Burgerschap Land van residentie Selfie - Gevraagde documenten + Vereiste documenten Upload een selfie waarop je het document vasthoudt + Vertaling Voorkant Upload een foto van de voorkant van het document Achterkant @@ -1248,6 +1277,57 @@ Nog geen documenten Je kunt je telefoonnummer, E-mailadres, identiteitsbewijs of woonadres toevoegen. Tik om fouten te corrigeren. + %1$s of %2$s + Je naam + Je naam in het %1$s + Je naam in de taal van het land (%1$s) van uitgifte. + Controleer of deze naam klopt:\n\n%1$s %2$s %3$s + Arabisch + Azerbeidzjaans + Bulgaars + Bangla + Tsjechisch + Deens + Duits + Divehi + Dzongkha + Grieks + Spaans + Estisch + Perzisch + Frans + Hebreeuws + Kroatisch + Hongaars + Armeens + Indonesisch + Ijslands + Italiaans + Japans + Georgisch + Khmer + Koreaans + Laotiaans + Litouws + Lets + Macedonisch + Mongools + Maleis + Birmaans + Nepalees + Nederlands + Pools + Portugees + Roemeens + Russisch + Slowaaks + Sloveens + Thai + Turkmeens + Turks + Oekraïens + Oesbeeks + Vietnamees Actieve sessies Huidige sessie @@ -1992,12 +2072,12 @@ **%1$d** uur **%1$d** uur **%1$d** uur - **%1$d** dag + **%1$d** dagen **%1$d** dag - **%1$d** dag - **%1$d** dag - **%1$d** dag - **%1$d** dag + **%1$d** dagen + **%1$d** dagen + **%1$d** dagen + **%1$d** dagen Bijlage: %1$d berichten Bijlage: 1 bericht diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 769fbdd61..e7f03482d 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -179,7 +179,7 @@ O **Telegram** precisa acessar seus contatos para que você possa se comunicar com seus amigos através de todos os seus dispositivos. Seus contatos serão continuamente sincronizados na nuvem fortemente criptografada do Telegram. AGORA NÃO CONTINUAR - Your contacts on Telegram + Seus contatos no Telegram Promover a administrador Nenhum usuário banido @@ -414,7 +414,7 @@ Enviar Stickers & GIFs Enviar mídia Enviar mensagem - Prévia de Links + Prévia de links Ler Mensagens alterou os privilégios de %1$s Alterar Info do canal @@ -517,7 +517,7 @@ %s convidou você para um chat secreto Você convidou %s para um chat secreto. Chats Secretos: - Criptografia de ponta-a-ponta + Criptografia de ponta a ponta Sem rastros nos servidores Timer de autodestruição Encaminhamento desativado @@ -962,10 +962,12 @@ O LED é uma pequena luz piscante em alguns dispositivos, utilizada para indicar novas mensagens. Nas prioridades mais altas as notificações irão funcionar mesmo que o seu celular esteja no modo Não Perturbe. Geral + Muted + Unmuted Ligado Desligado - Default (On) - Default (Off) + Padrão (Ligado) + Padrão (Desligado) Ativar Desativar Usuários Bloqueados @@ -1051,6 +1053,9 @@ Padrão Padrão Notificações Inteligentes + Exceptions + This section will list all chats with non-default notification settings.\n\nYou can customize notifications for a chat by opening its profile and choosing \'Notifications\'. + None %1$d / %2$s Desativado Frequência do Alerta de Som @@ -1117,6 +1122,7 @@ Streaming Streaming de Música e Vídeo Alguns vídeos não podem ser transmitidos por stream - ex: todos os vídeos enviados via Android utilizando o Telegram 4.7 ou inferiores. + Tap to change phone number Banco de Dados Local Limpar todos os textos em cache? @@ -1145,13 +1151,25 @@ With Telegram Passport you can easily sign up for websites and services that require identity verification.\n\nYour information, personal data, and documents are protected by end-to-end encryption. Nobody, including Telegram, can access them without your permission.\n\nYou can visit our FAQ to learn more. Please create a password to secure your personal data with end-to-end encryption.\n\nThis password will also be required whenever you log in to Telegram on a new device. CREATE A PASSWORD - Delete Passport + Delete Telegram Passport Are you sure you want to delete your Telegram Passport? Please use latin characters only. + Upload scans of verified translation of your passport. + Upload scans of verified translation of your internal passport. + Upload scans of verified translation of your driver licence. + Upload scans of verified translation of your identity card. Envie a digitalização de uma fatura de serviço Envie a digitalização do seu extrato bancário Envie a digitalização do seu contrato de locação + Envie uma digitalização da página de registro do passaporte. + Envie uma digitalização do seu registro temporário. Para confirmar seu endereço, envie uma digitalização ou foto do documento selecionado (todas as páginas). + Upload scans of verified translation of your utility bill. + Upload scans of verified translation of your bank statement. + Upload scans of verified translation of your tenancy agreement. + Upload scans of verified translation of your passport registration page. + Upload scans of verified translation of your temporary registration. + Please upload scans of verified translation of the selected document. Adicionar Fatura de Serviço Adicionar Extrato Bancário Adicionar Contrato de Aluguel @@ -1181,7 +1199,7 @@ Code Please enter the confirmation code we\'ve just sent to %1$s. Please enter your password to access your personal data. - %1$s requests access to your personal data to sign you up for their services. + **%1$s** requests access to your personal data to sign you up for their services. Please enter your Telegram Password to decrypt your data. You accept the *%1$s Privacy Policy* and allow their @%2$s to send you messages. You are sending your documents directly to %1$s and allowing their @%2$s to send you messages. @@ -1189,21 +1207,31 @@ Adicionar Passaporte Adicionar Passaporte Interno Registro do Passaporte - Envie uma digitalização da página de registro do passaporte. Registro Temporário - Envie uma digitalização do seu registro temporário. Adicionar Carteira de Identidade Adicionar Carteira de Motorista Personal Details Fill in your personal details Identity Document Upload a scan of your passport or other ID + Upload a scan of your passport + Upload a scan of your internal passport + Upload a scan of your identity card + Upload a scan of your driver\'s license Personal Details + Document Details Name + Middle name + Last name + Name (latin) + Middle name (latin) + Last name (latin) + Name (%1$s) + Middle name (%1$s) + Last name (%1$s) Select Gender Male Female - Surname Data de Nascimento Gender Document Number @@ -1213,6 +1241,7 @@ Selfie Required Documents Upload a selfie of yourself holding the document + Translation Front Side Upload a photo of the front side of the document Reverse Side @@ -1240,7 +1269,7 @@ Apagar digitalização? Upload Scans Upload Additional Scans - You can\'t upload more than %1$s files. + You can\'t upload more than %1$s. You can upload only image files. Scan Your Passport Scan your passport or identity card with machine-readable zone to fill personal details automatically. @@ -1248,6 +1277,57 @@ You have no documents yet You can add your phone number, email address, identity document or residential address. Tap to correct errors. + %1$s or %2$s + Your name + Your name in %1$s + Your name in the language of the country (%1$s) that issued the document. + Please check if this name is correct:\n\n%1$s %2$s %3$s + Arabic + Azerbaijani + Bulgarian + Bangla + Czech + Danish + German + Divehi + Dzongkha + Greek + Spanish + Estonian + Persian + French + Hebrew + Croatian + Hungarian + Armenian + Indonesian + Icelandic + Italian + Japanese + Georgian + Khmer + Korean + Lao + Lithuanian + Latvian + Macedonian + Mongolian + Malay + Burmese + Nepali + Dutch + Polish + Portuguese + Romanian + Russian + Slovak + Slovenian + Thai + Turkmen + Turkish + Ukrainian + Uzbek + Vietnamese Sessões Ativas Sessão atual @@ -1298,8 +1378,8 @@ ARQUIVOS MÍDIA LINKS - AUDIO - VOICE + ÁUDIO + VOZ Arquivos Compartilhados Mídia Compartilhada Links Compartilhados @@ -1308,12 +1388,12 @@ Compartilhe músicas nesse chat e acesse-as de qualquer um de seus dispositivos. Compartilhar arquivos e documentos no chat e acessá-los de qualquer um de seus dispositivos. Compartilhe links nesse chat e os acesse de qualquer um de seus dispositivos - Share voice messages in this chat and access them on any of your devices. + Compartilhe mensagens de voz nesta conversa e acesse de qualquer um de seus dispositivos. Fotos e vídeos desse chat serão mostrados aqui. Músicas desse chat serão mostradas aqui. Arquivos e documentos desse chat serão mostradas aqui. Links compartilhados desse chat serão mostrados aqui. - Voice messages from this chat will be shown here. + Mensagens de voz desta conversa serão mostradas aqui. Mapa Satélite @@ -1578,7 +1658,7 @@ Update app ATUALIZAR AGORA ATUALIZAR - LATER + DEPOIS Aceitar Concordo Rejeitar @@ -1715,7 +1795,7 @@ Desculpe, os administradores do grupo te restringiram do envio de mídias. We\'re very sorry, but this means you can\'t sign up for Telegram.\n\nUnlike others, we don\'t use your data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a feature-rich cloud service. You can adjust how we use your data (e.g., delete synced contacts) in Privacy & Security settings.\n\nBut if you\'re generally not OK with Telegram\'s modest needs, it won\'t be possible for us to provide this service. Age Verification - Privacy Policy and Terms of Service + Política de Privacidade e Termos de Serviço Tap Agree to confirm that you are %1$s or over. We\'re very sorry, but this means we must part ways here. Unlike others, we don\'t use your data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a feature-rich cloud service. You can adjust how we use your data (e.g., delete synced contacts) in Privacy & Security settings.\n\nBut if you\'re generally not OK with Telegram\'s modest needs, it won\'t be possible for us to provide this service. You can deactivate your account now — or look around some more and deactivate it later if you feel you\'re not happy with the way we use your data. Warning, this will irreversibly delete your Telegram account along with all the data you store in the Telegram cloud.\n\nImportant: You can Cancel now and export your data before deleting your account instead losing it all. (To do this, open the latest version of Telegram Desktop and go to Settings > Export Telegram Data.) diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index af229c3d6..c29f66d0c 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -962,6 +962,8 @@ LED is a small blinking light on some devices that is used to indicate new messages. Higher priority notifications will work even if your phone is in Do Not Disturb mode. General + Muted + Unmuted On Off Default (On) @@ -1051,6 +1053,9 @@ Default Default Smart Notifications + Exceptions + This section will list all chats with non-default notification settings.\n\nYou can customize notifications for a chat by opening its profile and choosing \'Notifications\'. + None %1$d / %2$s Disabled Sound Alert Frequency @@ -1078,6 +1083,7 @@ Disable in-app camera Reset Imported Contacts Clear sent media cache + Call settings You can change your language in the Settings later. Choose your language Other @@ -1117,6 +1123,7 @@ Streaming Stream Videos and Audio Files Some videos can\'t be streamed – e.g., all videos that were sent from Android using Telegram 4.7 and earlier versions.\n + Tap to change phone number Local Database Clear cached text messages? @@ -1148,10 +1155,22 @@ Delete Passport Are you sure you want to delete your Telegram Passport? Please use latin characters only. + Upload scans of verified translation of your passport. + Upload scans of verified translation of your internal passport. + Upload scans of verified translation of your driver licence. + Upload scans of verified translation of your identity card. Upload a scan of your utility bill. Upload a scan of your bank statement. Upload a scan of your tenancy agreement. + Upload a scan of your passport registration page. + Upload a scan of your temporary registration. To confirm your address, please upload a scan or photo of the selected document (all pages). + Upload scans of verified translation of your utility bill. + Upload scans of verified translation of your bank statement. + Upload scans of verified translation of your tenancy agreement. + Upload scans of verified translation of your passport registration page. + Upload scans of verified translation of your temporary registration. + Please upload scans of verified translation of the selected document. Add Utility Bill Add Bank Statement Add Tenancy Agreement @@ -1189,21 +1208,31 @@ Add Passport Add Internal Passport Passport Registration - Upload a scan of your passport registration page. Temporary Registration - Upload a scan of your temporary registration. Add Identity Card Add Driver Licence Personal Details Fill in your personal details Identity Document Upload a scan of your passport or other ID + Upload a scan of your passport + Upload a scan of your internal passport + Upload a scan of your identity card + Upload a scan of your driver\'s license Personal Details + Document Details Name + Middle name + Last name + Name (latin) + Middle name (latin) + Last name (latin) + Name (%1$s) + Middle name (%1$s) + Last name (%1$s) Select Gender Male Female - Surname Date of Birth Gender Document Number @@ -1213,6 +1242,7 @@ Selfie Required Documents Upload a selfie of yourself holding the document + Translation Front Side Upload a photo of the front side of the document Reverse Side @@ -1240,7 +1270,7 @@ Delete scan? Upload Scans Upload Additional Scans - You can\'t upload more than %1$s files. + You can\'t upload more than %1$s. You can upload only image files. Scan Your Passport Scan your passport or identity card with machine-readable zone to fill personal details automatically. @@ -1248,6 +1278,57 @@ You have no documents yet You can add your phone number, email address, identity document or residential address. Tap to correct errors. + %1$s or %2$s + Your name + Your name in %1$s + Your name in the language of the country (%1$s) that issued the document. + Please check if this name is correct:\n\n%1$s %2$s %3$s + Arabic + Azerbaijani + Bulgarian + Bangla + Czech + Danish + German + Divehi + Dzongkha + Greek + Spanish + Estonian + Persian + French + Hebrew + Croatian + Hungarian + Armenian + Indonesian + Icelandic + Italian + Japanese + Georgian + Khmer + Korean + Lao + Lithuanian + Latvian + Macedonian + Mongolian + Malay + Burmese + Nepali + Dutch + Polish + Portuguese + Romanian + Russian + Slovak + Slovenian + Thai + Turkmen + Turkish + Ukrainian + Uzbek + Vietnamese Active Sessions Current session diff --git a/build.gradle b/build.gradle index dee7a587f..a52999e7e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,13 @@ buildscript { repositories { jcenter() mavenCentral() + google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' - classpath 'com.google.gms:google-services:3.1.1' + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.gms:google-services:4.0.2' } +} +repositories { + google() } \ No newline at end of file