Commit a7513b3b authored by DrKLO's avatar DrKLO

Update to 3.7.0

parent 6154c891
## Telegram messenger for Android
[Telegram](http://telegram.org) is a messaging app with a focus on speed and security. It’s superfast, simple and free.
[Telegram](https://telegram.org) is a messaging app with a focus on speed and security. It’s superfast, simple and free.
This repo contains the official source code for [Telegram App for Android](https://play.google.com/store/apps/details?id=org.telegram.messenger).
##Creating your Telegram Application
......@@ -16,9 +16,9 @@ There are several things we require from **all developers** for the moment.
### API, Protocol documentation
Telegram API manuals: http://core.telegram.org/api
Telegram API manuals: https://core.telegram.org/api
MTproto protocol manuals: http://core.telegram.org/mtproto
MTproto protocol manuals: https://core.telegram.org/mtproto
### Usage
......
......@@ -5,7 +5,7 @@ repositories {
}
dependencies {
compile 'com.android.support:support-v4:23.1.+'
compile 'com.android.support:support-v4:23.2.1'
compile "com.google.android.gms:play-services-gcm:8.4.0"
compile "com.google.android.gms:play-services-maps:8.4.0"
compile 'net.hockeyapp.android:HockeySDK:3.6.+'
......@@ -63,6 +63,8 @@ android {
}
}
defaultConfig.versionCode = 767
sourceSets.main {
jniLibs.srcDir 'libs'
jni.srcDirs = [] //disable automatic ndk-build call
......@@ -80,10 +82,38 @@ android {
manifest.srcFile 'config/foss/AndroidManifest.xml'
}
productFlavors {
x86 {
ndk {
abiFilter "x86"
}
versionCode = 2
}
arm {
ndk {
abiFilter "armeabi"
}
versionCode = 0
}
armv7 {
ndk {
abiFilter "armeabi-v7a"
}
versionCode = 1
}
fat {
versionCode = 3
}
}
applicationVariants.all { variant ->
def abiVersion = variant.productFlavors.get(0).versionCode
variant.mergedFlavor.versionCode = defaultConfig.versionCode * 10 + abiVersion;
}
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionCode 755
versionName "3.6.1"
versionName "3.7.0"
}
}
......@@ -235,7 +235,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := tmessages.19
LOCAL_MODULE := tmessages.20
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
......
APP_PLATFORM := android-9
APP_ABI := armeabi armeabi-v7a x86
NDK_TOOLCHAIN_VERSION := 4.8
NDK_TOOLCHAIN_VERSION := 4.9
APP_STL := gnustl_static
\ No newline at end of file
......@@ -671,8 +671,7 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env
return result;
}
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t value) {
numBits = (unsigned int) (2 << (numBits - 1)) - 1;
static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t value) {
bytes += bitOffset / 8;
bitOffset %= 8;
*((int32_t *) bytes) |= (value << bitOffset);
......@@ -727,7 +726,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JN
for (int i = 0; i < resultSamples; i++) {
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
set_bits(bytes, i * 5, 5, value & 31);
set_bits(bytes, i * 5, value & 31);
}
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
......@@ -805,7 +804,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNI
for (int i = 0; i < resultSamples; i++) {
int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak);
set_bits(bytes, i * 5, 5, value & 31);
set_bits(bytes, i * 5, value & 31);
}
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
......
......@@ -5,6 +5,7 @@
#include <inttypes.h>
#include <stdlib.h>
#include <openssl/aes.h>
#include <unistd.h>
#include "utils.h"
#include "sqlite.h"
#include "image.h"
......
......@@ -8,8 +8,8 @@ jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
return JNI_VERSION_1_6;
}
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject object, int statementHandle) {
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv *env, jobject object, int statementHandle) {
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_step(handle);
if (errcode == SQLITE_ROW) {
......@@ -23,7 +23,7 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject o
}
int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobject object, int sqliteHandle, jstring sql) {
sqlite3* handle = (sqlite3 *)sqliteHandle;
sqlite3 *handle = (sqlite3 *) sqliteHandle;
char const *sqlStr = (*env)->GetStringUTFChars(env, sql, 0);
......@@ -41,11 +41,11 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobjec
(*env)->ReleaseStringUTFChars(env, sql, sqlStr);
}
return (int)stmt_handle;
return (int) stmt_handle;
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject object, int statementHandle) {
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_reset(handle);
if (SQLITE_OK != errcode) {
......@@ -54,16 +54,11 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobject object, int statementHandle) {
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
int errcode = sqlite3_finalize (handle);
if (SQLITE_OK != errcode) {
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
}
sqlite3_finalize((sqlite3_stmt *) statementHandle);
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env, jobject object, int statementHandle, int index, jobject value, int length) {
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
jbyte *buf = (*env)->GetDirectBufferAddress(env, value);
int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC);
......@@ -73,7 +68,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) {
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
char const *valueStr = (*env)->GetStringUTFChars(env, value, 0);
......@@ -88,7 +83,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jo
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobject object, int statementHandle, int index, int value) {
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_bind_int(handle, index, value);
if (SQLITE_OK != errcode) {
......@@ -97,7 +92,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobje
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobject object, int statementHandle, int index, long long value) {
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_bind_int64(handle, index, value);
if (SQLITE_OK != errcode) {
......@@ -105,8 +100,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobj
}
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jobject object, int statementHandle, int index, double value) {
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv *env, jobject object, int statementHandle, int index, double value) {
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_bind_double(handle, index, value);
if (SQLITE_OK != errcode) {
......@@ -114,8 +109,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jo
}
}
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv* env, jobject object, int statementHandle, int index) {
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv *env, jobject object, int statementHandle, int index) {
sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle;
int errcode = sqlite3_bind_null(handle, index);
if (SQLITE_OK != errcode) {
......
......@@ -57,7 +57,7 @@ void Connection::suspendConnection() {
}
void Connection::onReceivedData(NativeByteBuffer *buffer) {
//AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum);
AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum);
failedConnectionCount = 0;
......@@ -323,11 +323,11 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
uint32_t val = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0]);
uint32_t val2 = (bytes[7] << 24) | (bytes[6] << 16) | (bytes[5] << 8) | (bytes[4]);
if (bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val2 != 0x00000000) {
//bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef;
break;
}
}
/*for (int a = 0; a < 48; a++) {
for (int a = 0; a < 48; a++) {
temp[a] = bytes[55 - a];
}
......@@ -348,7 +348,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
memcpy(decryptIv, temp + 32, 16);
AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum);
memcpy(bytes + 56, temp + 56, 8);*/
memcpy(bytes + 56, temp + 56, 8);
firstPacketSent = true;
}
......@@ -358,7 +358,7 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
}
buffer->writeByte((uint8_t) packetLength);
bytes += (buffer->limit() - 1);
//AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum);
AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum);
} else {
packetLength = (packetLength << 8) + 0x7f;
if (reportAck) {
......@@ -366,13 +366,13 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
}
buffer->writeInt32(packetLength);
bytes += (buffer->limit() - 4);
//AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum);
AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum);
}
buffer->rewind();
writeBuffer(buffer);
buff->rewind();
//AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum);
AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum);
writeBuffer(buff);
}
......
......@@ -17,7 +17,7 @@
#define USE_DEBUG_SESSION false
#define READ_BUFFER_SIZE 1024 * 128
//#define DEBUG_VERSION
#define DEBUG_VERSION
#define DEFAULT_DATACENTER_ID INT_MAX
#define DC_UPDATE_TIME 60 * 60
#define DOWNLOAD_CONNECTIONS_COUNT 2
......
......@@ -99,6 +99,8 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="telegram.me" android:scheme="http" />
<data android:host="telegram.me" android:scheme="https" />
<data android:host="telegram.dog" android:scheme="http" />
<data android:host="telegram.dog" android:scheme="https" />
</intent-filter>
<intent-filter android:icon="@drawable/ic_launcher" android:priority="1">
<action android:name="android.intent.action.VIEW" />
......
......@@ -11,6 +11,7 @@ package org.telegram.messenger;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
......@@ -19,6 +20,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
......@@ -26,6 +28,7 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.Browser;
......@@ -84,7 +87,9 @@ public class AndroidUtilities {
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
private static int prevOrientation = -10;
private static boolean waitingForSms = false;
private static boolean waitingForCall = false;
private static final Object smsLock = new Object();
private static final Object callLock = new Object();
public static int statusBarHeight = 0;
public static float density = 1;
......@@ -240,6 +245,20 @@ public class AndroidUtilities {
}
}
public static boolean isWaitingForCall() {
boolean value;
synchronized (callLock) {
value = waitingForCall;
}
return value;
}
public static void setWaitingForCall(boolean value) {
synchronized (callLock) {
waitingForCall = value;
}
}
public static void showKeyboard(View view) {
if (view == null) {
return;
......@@ -422,11 +441,28 @@ public class AndroidUtilities {
if (context == null || uri == null) {
return;
}
try {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e);
intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1);
if (MediaController.getInstance().canCustomTabs()) {
intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null);
intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e);
intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1);
Intent actionIntent = new Intent(Intent.ACTION_SEND);
actionIntent.setType("text/plain");
actionIntent.putExtra(Intent.EXTRA_TEXT, uri.toString());
actionIntent.putExtra(Intent.EXTRA_SUBJECT, "");
PendingIntent pendingIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, actionIntent, PendingIntent.FLAG_ONE_SHOT);
Bundle bundle = new Bundle();
bundle.putInt("android.support.customtabs.customaction.ID", 0);
bundle.putParcelable("android.support.customtabs.customaction.ICON", BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha));
bundle.putString("android.support.customtabs.customaction.DESCRIPTION", LocaleController.getString("ShareFile", R.string.ShareFile));
bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent);
intent.putExtra("android.support.customtabs.extra.ACTION_BUTTON_BUNDLE", bundle);
intent.putExtra("android.support.customtabs.extra.TINT_ACTION_BUTTON", false);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
context.startActivity(intent);
} catch (Exception e) {
......@@ -917,7 +953,11 @@ public class AndroidUtilities {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
String value = cursor.getString(column_index);
if (value.startsWith("content://") || !value.startsWith("/") && !value.startsWith("file://")) {
return null;
}
return value;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
......
......@@ -37,6 +37,8 @@ import org.telegram.ui.Components.ForegroundDetector;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Locale;
public class ApplicationLoader extends Application {
......
......@@ -10,8 +10,8 @@ package org.telegram.messenger;
public class BuildVars {
public static boolean DEBUG_VERSION = false;
public static int BUILD_VERSION = 753;
public static String BUILD_VERSION_STRING = "3.6";
public static int BUILD_VERSION = 767;
public static String BUILD_VERSION_STRING = "3.7";
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";
......
......@@ -11,20 +11,24 @@ package org.telegram.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import org.telegram.PhoneFormat.PhoneFormat;
public class CallReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
/*TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
if (state == 1 && incomingNumber != null && incomingNumber.length() > 0) {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, incomingNumber);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, PhoneFormat.stripExceptNumbers(incomingNumber));
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);*/
}, PhoneStateListener.LISTEN_CALL_STATE);
}
}
......@@ -265,9 +265,9 @@ public class Emoji {
b = getBounds();
}
if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
//if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, paint);
}
//}
}
@Override
......
......@@ -550,13 +550,17 @@ public class FileLoader {
return getAttachFileName(sizeFull);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
if (sizes.size() > 0) {
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
if (sizeFull != null) {
return getAttachFileName(sizeFull);
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
if (message.media.webpage.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
if (sizes.size() > 0) {
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
if (sizeFull != null) {
return getAttachFileName(sizeFull);
}
}
} else if (message.media.webpage.document != null) {
return getAttachFileName(message.media.webpage.document);
}
}
}
......@@ -588,13 +592,17 @@ public class FileLoader {
return getPathToAttach(sizeFull);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
if (sizes.size() > 0) {
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
if (sizeFull != null) {
return getPathToAttach(sizeFull);
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
if (message.media.webpage.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
if (sizes.size() > 0) {
TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize());
if (sizeFull != null) {
return getPathToAttach(sizeFull);
}
}
} else if (message.media.webpage.document != null) {
return getPathToAttach(message.media.webpage.document);
}
}
}
......@@ -704,6 +712,23 @@ public class FileLoader {
return "";
}
public static String getDocumentExtension(TLRPC.Document document) {
String fileName = getDocumentFileName(document);
int idx = fileName.lastIndexOf(".");
String ext = null;
if (idx != -1) {
ext = fileName.substring(idx + 1);
}
if (ext == null || ext.length() == 0) {
ext = document.mime_type;
}
if (ext == null) {
ext = "";
}
ext = ext.toUpperCase();
return ext;
}
public static String getAttachFileName(TLObject attach) {
return getAttachFileName(attach, null);
}
......
......@@ -196,14 +196,17 @@ public class FileLog {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
File dir = new File (sdCard.getAbsolutePath() + "/logs");
File[] files = dir.listFiles();
for (File file : files) {
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
continue;
}
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
continue;
if (files != null) {
for (int a = 0; a < files.length; a++) {
File file = files[a];
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
continue;
}
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
continue;
}
file.delete();
}
file.delete();
}
}
}
......@@ -23,7 +23,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import org.telegram.tgnet.ConnectionsManager;
......@@ -33,7 +32,6 @@ import org.telegram.ui.Components.AnimatedFileDrawable;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
......@@ -2031,8 +2029,7 @@ public class ImageLoader {
public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight, boolean useMaxScale) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
FileDescriptor fileDescriptor = null;
ParcelFileDescriptor parcelFD = null;
InputStream inputStream = null;
if (path == null && uri != null && uri.getScheme() != null) {
String imageFilePath = null;
......@@ -2052,9 +2049,10 @@ public class ImageLoader {
} else if (uri != null) {
boolean error = false;
try {
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
fileDescriptor = parcelFD.getFileDescriptor();
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
BitmapFactory.decodeStream(inputStream, null, bmOptions);
inputStream.close();
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
} catch (Throwable e) {
FileLog.e("tmessages", e);
return null;
......@@ -2138,7 +2136,7 @@ public class ImageLoader {
}
} else if (uri != null) {
try {
b = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
b = BitmapFactory.decodeStream(inputStream, null, bmOptions);
if (b != null) {
if (bmOptions.inPurgeable) {
Utilities.pinBitmap(b);
......@@ -2153,7 +2151,7 @@ public class ImageLoader {
FileLog.e("tmessages", e);
} finally {
try {
parcelFD.close();
inputStream.close();
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
......
......@@ -322,7 +322,7 @@ public class LocaleController {
StringBuilder result = new StringBuilder(11);
result.append(languageCode);
if (countryCode.length() > 0 || variantCode.length() > 0) {
result.append('_');
result.append('-');
}
result.append(countryCode);
if (variantCode.length() > 0) {
......@@ -664,16 +664,21 @@ public class LocaleController {
}
public static String formatDateChat(long date) {
Calendar rightNow = Calendar.getInstance();
int year = rightNow.get(Calendar.YEAR);
try {
Calendar rightNow = Calendar.getInstance();
int year = rightNow.get(Calendar.YEAR);
rightNow.setTimeInMillis(date * 1000);
int dateYear = rightNow.get(Calendar.YEAR);
rightNow.setTimeInMillis(date * 1000);
int dateYear = rightNow.get(Calendar.YEAR);
if (year == dateYear) {
return getInstance().chatDate.format(date * 1000);
if (year == dateYear) {
return getInstance().chatDate.format(date * 1000);
}
return getInstance().chatFullDate.format(date * 1000);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return getInstance().chatFullDate.format(date * 1000);
return "LOC_ERR: formatDateChat";
}
public static String formatDate(long date) {
......@@ -697,7 +702,7 @@ public class LocaleController {
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return "LOC_ERR";
return "LOC_ERR: formatDate";
}
public static String formatDateAudio(long date) {
......
......@@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
public class NativeLoader {
private final static int LIB_VERSION = 19;
private final static int LIB_VERSION = 20;
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";
......
......@@ -53,6 +53,7 @@ public class NotificationCenter {
public static final int didSetTwoStepPassword = totalEvents++;
public static final int screenStateChanged = totalEvents++;
public static final int didLoadedReplyMessages = totalEvents++;
public static final int didLoadedPinnedMessage = totalEvents++;
public static final int newSessionReceived = totalEvents++;
public static final int didReceivedWebpages = totalEvents++;
public static final int didReceivedWebpagesInUpdates = totalEvents++;
......@@ -60,6 +61,7 @@ public class NotificationCenter {
public static final int didReplacedPhotoInMemCache = totalEvents++;
public static final int messagesReadContent = totalEvents++;
public static final int botInfoDidLoaded = totalEvents++;
public static final int userInfoDidLoaded = totalEvents++;
public static final int botKeyboardDidLoaded = totalEvents++;
public static final int chatSearchResultsAvailable = totalEvents++;
public static final int musicDidLoaded = totalEvents++;
......@@ -67,6 +69,7 @@ public class NotificationCenter {
public static final int didUpdatedMessagesViews = totalEvents++;
public static final int needReloadRecentDialogsSearch = totalEvents++;
public static final int locationPermissionGranted = totalEvents++;
public static final int peerSettingsDidLoaded = totalEvents++;
public static final int httpFileDidLoaded = totalEvents++;
public static final int httpFileDidFailedLoad = totalEvents++;
......
......@@ -820,6 +820,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
req.message = message;
req.id = messageObject.getId();
req.no_webpage = !searchLinks;
FileLog.d("tmessages", "try to edit message " + req.id + " in channel " + req.channel.channel_id + " hash " + req.channel.access_hash + " message " + req.message);
final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
......@@ -2002,6 +2003,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (!isSentError) {
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id); //TODO remove later?
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
@Override
public void run() {
......@@ -2274,7 +2276,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (extension == null) {
extension = "txt";
}
path = MediaController.copyDocumentToCache(uri, extension);
path = MediaController.copyFileToCache(uri, extension);
if (path == null) {
return false;
}
......@@ -2923,12 +2925,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (MediaController.isGif(uri)) {
isDocument = true;
originalPath = uri.toString();
tempPath = MediaController.copyDocumentToCache(uri, "gif");
tempPath = MediaController.copyFileToCache(uri, "gif");
extension = "gif";
} else if (MediaController.isWebp(uri)) {
isDocument = true;
originalPath = uri.toString();
tempPath = MediaController.copyDocumentToCache(uri, "webp");
tempPath = MediaController.copyFileToCache(uri, "webp");
extension = "webp";
}
}
......@@ -3009,8 +3011,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
TLRPC.TL_document document = null;
if (!isEncrypted) {
TLObject object = MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
document = (TLRPC.TL_document) object;
//document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5);
}
if (document == null) {
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND);
......
......@@ -9,8 +9,10 @@
package org.telegram.messenger;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
......@@ -48,6 +50,11 @@ public class TgChooserTargetService extends ChooserTargetService {
if (!UserConfig.isClientActivated()) {
return targets;
}
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
if (!preferences.getBoolean("direct_share", true)) {
return targets;
}
ImageLoader imageLoader = ImageLoader.getInstance();
final Semaphore semaphore = new Semaphore(0);
final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName());
......
......@@ -179,7 +179,7 @@ public class BotQuery {
}
public static void putBotInfo(final TLRPC.BotInfo botInfo) {
if (botInfo == null || botInfo instanceof TLRPC.TL_botInfoEmpty) {
if (botInfo == null) {
return;
}
botInfos.put(botInfo.user_id, botInfo);
......
......@@ -22,9 +22,6 @@ import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import org.telegram.messenger.support.util.ThreadUtil;
import org.telegram.messenger.support.util.TileList;
/**
* A utility class that supports asynchronous content loading.
* <p>
......@@ -42,7 +39,7 @@ import org.telegram.messenger.support.util.TileList;
* Note that this class uses a single thread to load the data, so it suitable to load data from
* secondary storage such as disk, but not from network.
* <p>
* This class is designed to work with {@link org.telegram.messenger.support.widget.RecyclerView}, but it does
* This class is designed to work with {@link android.support.v7.widget.RecyclerView}, but it does
* not depend on it and can be used with other list views.
*
*/
......@@ -113,7 +110,7 @@ public class AsyncListUtil<T> {
* <p>
* Identifies the data items that have not been loaded yet and initiates loading them in the
* background. Should be called from the view's scroll listener (such as
* {@link org.telegram.messenger.support.widget.RecyclerView.OnScrollListener#onScrolled}).
* {@link android.support.v7.widget.RecyclerView.OnScrollListener#onScrolled}).
*/
public void onRangeChanged() {
if (isRefreshPending()) {
......
......@@ -18,10 +18,11 @@ package org.telegram.messenger.support.util;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.content.ParallelExecutorCompat;
import android.util.Log;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
class MessageThreadUtil<T> implements ThreadUtil<T> {
......@@ -83,7 +84,8 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
return new BackgroundCallback<T>() {
final private MessageQueue mQueue = new MessageQueue();
final private Executor mExecutor = Executors.newSingleThreadExecutor();
final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor();
AtomicBoolean mBackgroundRunning = new AtomicBoolean(false);
private static final int REFRESH = 1;
private static final int UPDATE_RANGE = 2;
......@@ -114,42 +116,51 @@ class MessageThreadUtil<T> implements ThreadUtil<T> {
private void sendMessage(SyncQueueItem msg) {
mQueue.sendMessage(msg);
mExecutor.execute(mBackgroundRunnable);
maybeExecuteBackgroundRunnable();
}
private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
mQueue.sendMessageAtFrontOfQueue(msg);
mExecutor.execute(mBackgroundRunnable);
maybeExecuteBackgroundRunnable();
}
private void maybeExecuteBackgroundRunnable() {
if (mBackgroundRunning.compareAndSet(false, true)) {
mExecutor.execute(mBackgroundRunnable);
}
}
private Runnable mBackgroundRunnable = new Runnable() {
@Override
public void run() {
SyncQueueItem msg = mQueue.next();
if (msg == null) {
return;
}
switch (msg.what) {
case REFRESH:
mQueue.removeMessages(REFRESH);
callback.refresh(msg.arg1);
while (true) {
SyncQueueItem msg = mQueue.next();
if (msg == null) {
break;
case UPDATE_RANGE:
mQueue.removeMessages(UPDATE_RANGE);
mQueue.removeMessages(LOAD_TILE);
callback.updateRange(
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
break;
case LOAD_TILE:
callback.loadTile(msg.arg1, msg.arg2);
break;
case RECYCLE_TILE:
//noinspection unchecked
callback.recycleTile((TileList.Tile<T>) msg.data);
break;
default:
Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
}
switch (msg.what) {
case REFRESH:
mQueue.removeMessages(REFRESH);
callback.refresh(msg.arg1);
break;
case UPDATE_RANGE:
mQueue.removeMessages(UPDATE_RANGE);
mQueue.removeMessages(LOAD_TILE);
callback.updateRange(
msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
break;
case LOAD_TILE:
callback.loadTile(msg.arg1, msg.arg2);
break;
case RECYCLE_TILE:
//noinspection unchecked
callback.recycleTile((TileList.Tile<T>) msg.data);
break;
default:
Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
}
}
mBackgroundRunning.set(false);
}
};
};
......
......@@ -24,7 +24,7 @@ import java.util.Comparator;
/**
* A Sorted list implementation that can keep items in order and also notify for changes in the
* list
* such that it can be bound to a {@link org.telegram.messenger.support.widget.RecyclerView.Adapter
* such that it can be bound to a {@link android.support.v7.widget.RecyclerView.Adapter
* RecyclerView.Adapter}.
* <p>
* It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses
......@@ -737,7 +737,7 @@ public class SortedList<T> {
* so
* that you can change its behavior depending on your UI.
* <p>
* For example, if you are using SortedList with a {@link org.telegram.messenger.support.widget.RecyclerView.Adapter
* For example, if you are using SortedList with a {@link android.support.v7.widget.RecyclerView.Adapter
* RecyclerView.Adapter}, you should
* return whether the items' visual representations are the same or not.
*
......
......@@ -16,8 +16,6 @@
package org.telegram.messenger.support.util;
import org.telegram.messenger.support.util.TileList;
interface ThreadUtil<T> {
interface MainThreadCallback<T> {
......
......@@ -19,9 +19,6 @@ package org.telegram.messenger.support.widget;
import android.support.v4.util.Pools;
import android.util.Log;
import org.telegram.messenger.support.widget.OpReorderer;
import org.telegram.messenger.support.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
......@@ -70,6 +67,8 @@ class AdapterHelper implements OpReorderer.Callback {
final OpReorderer mOpReorderer;
private int mExistingUpdateTypes = 0;
AdapterHelper(Callback callback) {
this(callback, false);
}
......@@ -88,6 +87,7 @@ class AdapterHelper implements OpReorderer.Callback {
void reset() {
recycleUpdateOpsAndClearList(mPendingUpdates);
recycleUpdateOpsAndClearList(mPostponedList);
mExistingUpdateTypes = 0;
}
void preProcess() {
......@@ -122,6 +122,7 @@ class AdapterHelper implements OpReorderer.Callback {
mCallback.onDispatchSecondPass(mPostponedList.get(i));
}
recycleUpdateOpsAndClearList(mPostponedList);
mExistingUpdateTypes = 0;
}
private void applyMove(UpdateOp op) {
......@@ -460,6 +461,10 @@ class AdapterHelper implements OpReorderer.Callback {
return mPendingUpdates.size() > 0;
}
boolean hasAnyUpdateTypes(int updateTypes) {
return (mExistingUpdateTypes & updateTypes) != 0;
}
int findPositionOffset(int position) {
return findPositionOffset(position, 0);
}
......@@ -498,6 +503,7 @@ class AdapterHelper implements OpReorderer.Callback {
*/
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
mExistingUpdateTypes |= UpdateOp.UPDATE;
return mPendingUpdates.size() == 1;
}
......@@ -506,6 +512,7 @@ class AdapterHelper implements OpReorderer.Callback {
*/
boolean onItemRangeInserted(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
mExistingUpdateTypes |= UpdateOp.ADD;
return mPendingUpdates.size() == 1;
}
......@@ -514,6 +521,7 @@ class AdapterHelper implements OpReorderer.Callback {
*/
boolean onItemRangeRemoved(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
mExistingUpdateTypes |= UpdateOp.REMOVE;
return mPendingUpdates.size() == 1;
}
......@@ -522,12 +530,13 @@ class AdapterHelper implements OpReorderer.Callback {
*/
boolean onItemRangeMoved(int from, int to, int itemCount) {
if (from == to) {
return false;//no-op
return false; // no-op
}
if (itemCount != 1) {
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
}
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
mExistingUpdateTypes |= UpdateOp.MOVE;
return mPendingUpdates.size() == 1;
}
......@@ -564,6 +573,7 @@ class AdapterHelper implements OpReorderer.Callback {
}
}
recycleUpdateOpsAndClearList(mPendingUpdates);
mExistingUpdateTypes = 0;
}
public int applyPendingUpdatesToPosition(int position) {
......@@ -602,18 +612,22 @@ class AdapterHelper implements OpReorderer.Callback {
return position;
}
boolean hasUpdates() {
return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty();
}
/**
* Queued operation to happen when child views are updated.
*/
static class UpdateOp {
static final int ADD = 0;
static final int ADD = 1;
static final int REMOVE = 1;
static final int REMOVE = 1 << 1;
static final int UPDATE = 2;
static final int UPDATE = 1 << 2;
static final int MOVE = 3;
static final int MOVE = 1 << 3;
static final int POOL_SIZE = 30;
......
......@@ -208,8 +208,8 @@ class ChildHelper {
for (int i = 0; i < count; i++) {
final View view = mHiddenViews.get(i);
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
if (holder.getLayoutPosition() == position && !holder.isInvalid() &&
(type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved()
&& (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
return view;
}
}
......@@ -339,6 +339,25 @@ class ChildHelper {
}
}
/**
* Moves a child view from hidden list to regular list.
* Calling this method should probably be followed by a detach, otherwise, it will suddenly
* show up in LayoutManager's children list.
*
* @param view The hidden View to unhide
*/
void unhide(View view) {
final int offset = mCallback.indexOfChild(view);
if (offset < 0) {
throw new IllegalArgumentException("view is not a child, cannot hide " + view);
}
if (!mBucket.get(offset)) {
throw new RuntimeException("trying to unhide a view that was not hidden" + view);
}
mBucket.clear(offset);
unhideViewInternal(view);
}
@Override
public String toString() {
return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
......
......@@ -15,12 +15,11 @@
*/
package org.telegram.messenger.support.widget;
import android.support.annotation.NonNull;
import android.support.v4.animation.AnimatorCompatHelper;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import org.telegram.messenger.support.widget.RecyclerView;
import org.telegram.messenger.support.widget.RecyclerView.ViewHolder;
import android.view.View;
......@@ -34,23 +33,22 @@ import java.util.List;
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
public class DefaultItemAnimator extends SimpleItemAnimator {
private static final boolean DEBUG = false;
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
new ArrayList<ArrayList<ViewHolder>>();
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
private static class MoveInfo {
public ViewHolder holder;
......@@ -112,7 +110,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
final ArrayList<MoveInfo> moves = new ArrayList<>();
moves.addAll(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
......@@ -136,7 +134,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
final ArrayList<ChangeInfo> changes = new ArrayList<>();
changes.addAll(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
......@@ -159,7 +157,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
}
// Next, add stuff
if (additionsPending) {
final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
final ArrayList<ViewHolder> additions = new ArrayList<>();
additions.addAll(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
......@@ -312,6 +310,11 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
@Override
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
// Don't know how to run change animations when the same view holder is re-used.
// run a move animation to handle position changes.
return animateMove(oldHolder, fromX, fromY, toX, toY);
}
final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
......@@ -322,7 +325,7 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
if (newHolder != null && newHolder.itemView != null) {
if (newHolder != null) {
// carry over translation values
resetAnimation(newHolder);
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
......@@ -481,21 +484,25 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
}
// animations should be ended by the cancel above.
//noinspection PointlessBooleanExpression,ConstantConditions
if (mRemoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mAddAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mChangeAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mMoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
......@@ -626,6 +633,28 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
}
}
/**
* {@inheritDoc}
* <p>
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
* When this is the case:
* <ul>
* <li>If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both
* ViewHolder arguments will be the same instance.
* </li>
* <li>
* If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)},
* then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and
* run a move animation instead.
* </li>
* </ul>
*/
@Override
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
@Override
public void onAnimationStart(View view) {}
......@@ -635,5 +664,5 @@ public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
@Override
public void onAnimationCancel(View view) {}
};
}
}
......@@ -15,6 +15,7 @@
*/
package org.telegram.messenger.support.widget;
import android.view.View;
/**
......@@ -35,8 +36,11 @@ class LayoutState {
final static int ITEM_DIRECTION_TAIL = 1;
final static int SCOLLING_OFFSET_NaN = Integer.MIN_VALUE;
/**
* We may not want to recycle children in some cases (e.g. layout)
*/
boolean mRecycle = true;
/**
* Number of pixels that we should fill, in the layout direction.
*/
......@@ -69,6 +73,16 @@ class LayoutState {
*/
int mEndLine = 0;
/**
* If true, layout should stop if a focusable view is added
*/
boolean mStopInFocusable;
/**
* If the content is not wrapped with any value
*/
boolean mInfinite;
/**
* @return true if there are more items in the data adapter
*/
......
......@@ -24,8 +24,6 @@ import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import org.telegram.messenger.support.widget.RecyclerView;
/**
* {@link RecyclerView.SmoothScroller} implementation which uses
* {@link android.view.animation.LinearInterpolator} until the target position becames a child of
......@@ -124,6 +122,7 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
stop();
return;
}
//noinspection PointlessBooleanExpression
if (DEBUG && mTargetVector != null
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
throw new IllegalStateException("Scroll happened in the opposite direction"
......@@ -293,13 +292,13 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
* @param view The view which we want to make fully visible
* @param snapPreference The edge which the view should snap to when entering the visible
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
* {@link #SNAP_TO_END}.
* {@link #SNAP_TO_ANY}.
* @return The vertical scroll amount necessary to make the view visible with the given
* snap preference.
*/
public int calculateDyToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollVertically()) {
if (layoutManager == null || !layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
......@@ -324,7 +323,7 @@ abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
*/
public int calculateDxToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollHorizontally()) {
if (layoutManager == null || !layoutManager.canScrollHorizontally()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
......
......@@ -22,8 +22,6 @@ import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import org.telegram.messenger.support.widget.RecyclerView;
/**
* The AccessibilityDelegate used by RecyclerView.
* <p>
......
......@@ -17,8 +17,6 @@ package org.telegram.messenger.support.widget;
import android.view.View;
import org.telegram.messenger.support.widget.RecyclerView;
/**
* A helper class to do scroll offset calculations.
*/
......
......@@ -67,8 +67,9 @@ public class Track {
samplingFrequencyIndexMap.put(8000, 0xb);
}
public Track(int id, MediaFormat format, boolean isAudio) throws Exception {
public Track(int id, MediaFormat format, boolean audio) throws Exception {
trackId = id;
isAudio = audio;
if (!isAudio) {
sampleDurations.add((long) 3015);
duration = 3015;
......@@ -136,7 +137,6 @@ public class Track {
} else {
sampleDurations.add((long) 1024);
duration = 1024;
isAudio = true;
volume = 1;
timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
handler = "soun";
......@@ -184,15 +184,18 @@ public class Track {
}
public void addSample(long offset, MediaCodec.BufferInfo bufferInfo) {
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
if (delta < 0) {
return;
}
boolean isSyncFrame = !isAudio && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
samples.add(new Sample(offset, bufferInfo.size));
if (syncSamples != null && isSyncFrame) {
syncSamples.add(samples.size());
}
long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs;
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
delta = (delta * timeScale + 500000L) / 1000000L;
lastPresentationTimeUs = bufferInfo.presentationTimeUs;
if (!first) {
sampleDurations.add(sampleDurations.size() - 1, delta);
duration += delta;
......
......@@ -238,7 +238,7 @@ public class ContactsAdapter extends BaseSectionsAdapter {
}
} else if (type == 0) {
if (convertView == null) {
convertView = new UserCell(mContext, 58, 1);
convertView = new UserCell(mContext, 58, 1, false);
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
}
......
......@@ -94,6 +94,7 @@ public class DialogsAdapter extends RecyclerView.Adapter {
} else if (viewType == 1) {
view = new LoadingCell(mContext);
}
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
return new Holder(view);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment