Commit 06473773 authored by DrKLO's avatar DrKLO

Update to 3.8.1

parent a7513b3b
......@@ -5,7 +5,7 @@ repositories {
}
dependencies {
compile 'com.android.support:support-v4:23.2.1'
compile 'com.android.support:support-v4:23.3.0'
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.+'
......@@ -14,7 +14,7 @@ dependencies {
android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
buildToolsVersion '23.0.3'
useLibrary 'org.apache.http.legacy'
defaultConfig.applicationId = "org.telegram.messenger"
......@@ -63,7 +63,7 @@ android {
}
}
defaultConfig.versionCode = 767
defaultConfig.versionCode = 787
sourceSets.main {
jniLibs.srcDir 'libs'
......@@ -114,6 +114,8 @@ android {
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionName "3.7.0"
versionName "3.8.1"
}
}
apply plugin: 'com.google.gms.google-services'
{
"project_info": {
"project_id": "tmessages2",
"project_number": "760348033671",
"name": "Telegram"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:760348033671:android:f6afd7b67eae3860",
"client_id": "android:org.telegram.messenger",
"client_type": 1,
"android_client_info": {
"package_name": "org.telegram.messenger",
"certificate_hash": []
}
},
"oauth_client": [],
"api_key": [],
"services": {
"analytics_service": {
"status": 1
},
"cloud_messaging_service": {
"status": 2,
"apns_config": []
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"google_signin_service": {
"status": 1
},
"ads_service": {
"status": 1
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:760348033671:android:dc022572c167a16c",
"client_id": "android:org.telegram.messenger.beta",
"client_type": 1,
"android_client_info": {
"package_name": "org.telegram.messenger.beta",
"certificate_hash": []
}
},
"oauth_client": [],
"api_key": [],
"services": {
"analytics_service": {
"status": 1
},
"cloud_messaging_service": {
"status": 2,
"apns_config": []
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"google_signin_service": {
"status": 1
},
"ads_service": {
"status": 1
}
}
}
],
"client_info": [],
"ARTIFACT_VERSION": "1"
}
\ No newline at end of file
......@@ -235,12 +235,12 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := tmessages.20
LOCAL_MODULE := tmessages.21
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -Os -funroll-loops -std=c++11
LOCAL_LDLIBS := -ljnigraphics -llog -lz
LOCAL_LDLIBS := -ljnigraphics -llog -lz -latomic
LOCAL_STATIC_LIBRARIES := webp sqlite tgnet breakpad avformat avcodec avutil
LOCAL_SRC_FILES := \
......
......@@ -157,6 +157,10 @@ void setNetworkAvailable(JNIEnv *env, jclass c, jboolean value) {
ConnectionsManager::getInstance().setNetworkAvailable(value);
}
void setPushConnectionEnabled(JNIEnv *env, jclass c, jboolean value) {
ConnectionsManager::getInstance().setPushConnectionEnabled(value);
}
class Delegate : public ConnectiosManagerDelegate {
void onUpdate() {
......@@ -194,7 +198,7 @@ class Delegate : public ConnectiosManagerDelegate {
}
};
void init(JNIEnv *env, jclass c, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring configPath, jstring logPath, jint userId) {
void init(JNIEnv *env, jclass c, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring configPath, jstring logPath, jint userId, jboolean enablePushConnection) {
const char *deviceModelStr = env->GetStringUTFChars(deviceModel, 0);
const char *systemVersionStr = env->GetStringUTFChars(systemVersion, 0);
const char *appVersionStr = env->GetStringUTFChars(appVersion, 0);
......@@ -202,7 +206,7 @@ void init(JNIEnv *env, jclass c, jint version, jint layer, jint apiId, jstring d
const char *configPathStr = env->GetStringUTFChars(configPath, 0);
const char *logPathStr = env->GetStringUTFChars(logPath, 0);
ConnectionsManager::getInstance().init(version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(configPathStr), std::string(logPathStr), userId, true);
ConnectionsManager::getInstance().init(version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(configPathStr), std::string(logPathStr), userId, true, enablePushConnection);
if (deviceModelStr != 0) {
env->ReleaseStringUTFChars(deviceModel, deviceModelStr);
......@@ -242,13 +246,14 @@ static JNINativeMethod ConnectionsManagerMethods[] = {
{"native_applyDatacenterAddress", "(ILjava/lang/String;I)V", (void *) applyDatacenterAddress},
{"native_getConnectionState", "()I", (void *) getConnectionState},
{"native_setUserId", "(I)V", (void *) setUserId},
{"native_init", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V", (void *) init},
{"native_init", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)V", (void *) init},
{"native_switchBackend", "()V", (void *) switchBackend},
{"native_pauseNetwork", "()V", (void *) pauseNetwork},
{"native_resumeNetwork", "(Z)V", (void *) resumeNetwork},
{"native_updateDcSettings", "()V", (void *) updateDcSettings},
{"native_setUseIpv6", "(Z)V", (void *) setUseIpv6},
{"native_setNetworkAvailable", "(Z)V", (void *) setNetworkAvailable},
{"native_setPushConnectionEnabled", "(Z)V", (void *) setPushConnectionEnabled},
{"native_setJava", "(Z)V", (void *) setJava}
};
......
......@@ -397,13 +397,13 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_calcCDT(JNIEnv *env, jclass
JNIEXPORT int Java_org_telegram_messenger_Utilities_pinBitmap(JNIEnv *env, jclass class, jobject bitmap) {
if (bitmap == NULL) {
return;
return 0;
}
unsigned char *pixels;
return AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0 ? 1 : 0;
}
JNIEXPORT int Java_org_telegram_messenger_Utilities_unpinBitmap(JNIEnv *env, jclass class, jobject bitmap) {
JNIEXPORT void Java_org_telegram_messenger_Utilities_unpinBitmap(JNIEnv *env, jclass class, jobject bitmap) {
if (bitmap == NULL) {
return;
}
......
......@@ -394,7 +394,7 @@ void Connection::onDisconnected(int reason) {
ConnectionsManager::getInstance().onConnectionClosed(this);
uint32_t datacenterId = currentDatacenter->getDatacenterId();
if (connectionState == TcpConnectionStageIdle && connectionType == ConnectionTypeGeneric && (datacenterId == ConnectionsManager::getInstance().currentDatacenterId || datacenterId == ConnectionsManager::getInstance().movingToDatacenterId)) {
if (connectionState == TcpConnectionStageIdle && connectionType == ConnectionTypeGeneric && (currentDatacenter->isHandshaking() || datacenterId == ConnectionsManager::getInstance().currentDatacenterId || datacenterId == ConnectionsManager::getInstance().movingToDatacenterId)) {
connectionState = TcpConnectionStageReconnecting;
failedConnectionCount++;
if (failedConnectionCount == 1) {
......
......@@ -170,22 +170,24 @@ void ConnectionsManager::select() {
}
Datacenter *datacenter = getDatacenterWithId(currentDatacenterId);
if ((sendingPushPing && abs(now - lastPushPingTime) >= 30000) || abs(now - lastPushPingTime) >= 60000 * 3 + 10000) {
lastPushPingTime = 0;
sendingPushPing = false;
if (datacenter != nullptr) {
Connection *connection = datacenter->getPushConnection(false);
if (connection != nullptr) {
connection->suspendConnection();
if (pushConnectionEnabled) {
if ((sendingPushPing && abs(now - lastPushPingTime) >= 30000) || abs(now - lastPushPingTime) >= 60000 * 3 + 10000) {
lastPushPingTime = 0;
sendingPushPing = false;
if (datacenter != nullptr) {
Connection *connection = datacenter->getPushConnection(false);
if (connection != nullptr) {
connection->suspendConnection();
}
}
DEBUG_D("push ping timeout");
}
DEBUG_D("push ping timeout");
}
if (abs(now - lastPushPingTime) >= 60000 * 3) {
DEBUG_D("time for push ping");
lastPushPingTime = now;
if (datacenter != nullptr) {
sendPing(datacenter, true);
if (abs(now - lastPushPingTime) >= 60000 * 3) {
DEBUG_D("time for push ping");
lastPushPingTime = now;
if (datacenter != nullptr) {
sendPing(datacenter, true);
}
}
}
......@@ -220,7 +222,7 @@ void ConnectionsManager::select() {
return;
} else {
lastPauseTime = now;
DEBUG_D("don't sleep 30 seconds because of salt, upload or download request");
DEBUG_D("don't sleep because of salt, upload or download request");
}
}
if (networkPaused) {
......@@ -285,7 +287,7 @@ void *ConnectionsManager::ThreadProc(void *data) {
javaVm->AttachCurrentThread(&jniEnv, NULL);
#endif
ConnectionsManager *networkManager = (ConnectionsManager *) (data);
if (networkManager->currentUserId != 0) {
if (networkManager->currentUserId != 0 && networkManager->pushConnectionEnabled) {
Datacenter *datacenter = networkManager->getDatacenterWithId(networkManager->currentDatacenterId);
if (datacenter != nullptr) {
datacenter->createPushConnection()->setSessionId(networkManager->pushSessionId);
......@@ -595,7 +597,6 @@ void ConnectionsManager::onConnectionConnected(Connection *connection) {
} else {
if (networkPaused && lastPauseTime != 0) {
lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 30000;
}
processRequestQueue(connection->getConnectionType(), datacenter->getDatacenterId());
}
......@@ -1210,7 +1211,6 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
if (connection->connectionType == ConnectionTypePush) {
if (networkPaused) {
lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 30000;
DEBUG_D("received internal push: wakeup network in background");
} else if (lastPauseTime != 0) {
lastPauseTime = getCurrentTimeMillis();
......@@ -1234,7 +1234,7 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
}
void ConnectionsManager::sendPing(Datacenter *datacenter, bool usePushConnection) {
if (usePushConnection && currentUserId == 0) {
if (usePushConnection && (currentUserId == 0 || !usePushConnection)) {
return;
}
Connection *connection = nullptr;
......@@ -1401,7 +1401,7 @@ void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete
request->ptr1 = ptr1;
request->ptr2 = ptr2;
request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request);
DEBUG_D("send request wrapped %p - %s", request->rpcRequest.get(), typeid(*request->rpcRequest.get()).name());
DEBUG_D("send request wrapped %p - %s", request->rpcRequest.get(), typeid(*(request->rpcRequest.get())).name());
requestsQueue.push_back(std::unique_ptr<Request>(request));
if (immediate) {
processRequestQueue(0, 0);
......@@ -1452,7 +1452,7 @@ void ConnectionsManager::setUserId(int32_t userId) {
if (currentUserId != userId && userId != 0) {
updateDcSettings(0);
}
if (currentUserId != 0) {
if (currentUserId != 0 && pushConnectionEnabled) {
Datacenter *datacenter = getDatacenterWithId(currentDatacenterId);
if (datacenter != nullptr) {
datacenter->createPushConnection()->setSessionId(pushSessionId);
......@@ -2121,7 +2121,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
request->outgoingQuery = message->outgoingBody;
message->outgoingBody = nullptr;
} else {
DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg", message->body.get(), typeid(*message->body.get()).name());
DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg", message->body.get(), typeid(*(message->body.get())).name());
request->query = std::move(message->body);
}
message->body = std::unique_ptr<TLObject>(request);
......@@ -2390,7 +2390,23 @@ void ConnectionsManager::setDelegate(ConnectiosManagerDelegate *connectiosManage
delegate = connectiosManagerDelegate;
}
void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused) {
void ConnectionsManager::setPushConnectionEnabled(bool value) {
pushConnectionEnabled = value;
Datacenter *datacenter = getDatacenterWithId(currentDatacenterId);
if (datacenter != nullptr) {
if (!pushConnectionEnabled) {
Connection *connection = datacenter->getPushConnection(false);
if (connection != nullptr) {
connection->suspendConnection();
}
} else {
datacenter->createPushConnection()->setSessionId(pushSessionId);
sendPing(datacenter, true);
}
}
}
void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection) {
currentVersion = version;
currentLayer = layer;
currentApiId = apiId;
......@@ -2401,6 +2417,7 @@ void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, st
currentLangCode = langCode;
currentUserId = userId;
currentLogPath = logPath;
pushConnectionEnabled = enablePushConnection;
if (isPaused) {
lastPauseTime = getCurrentTimeMillis();
}
......@@ -2423,7 +2440,6 @@ void ConnectionsManager::resumeNetwork(bool partial) {
if (partial) {
if (networkPaused) {
lastPauseTime = getCurrentTimeMillis();
nextSleepTimeout = 30000;
networkPaused = false;
DEBUG_D("wakeup network in background");
} else if (lastPauseTime != 0) {
......
......@@ -60,8 +60,9 @@ public:
void pauseNetwork();
void setNetworkAvailable(bool value);
void setUseIpv6(bool value);
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused);
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection);
void updateDcSettings(uint32_t datacenterId);
void setPushConnectionEnabled(bool value);
#ifdef ANDROID
void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2);
......@@ -133,7 +134,7 @@ private:
int32_t lastDcUpdateTime = 0;
int64_t lastPingTime = getCurrentTimeMillis();
bool networkPaused = false;
int32_t nextSleepTimeout = 30000;
int32_t nextSleepTimeout = CONNECTION_BACKGROUND_KEEP_TIME;
int64_t lastPauseTime = 0;
ConnectionState connectionState = ConnectionStateConnecting;
std::unique_ptr<ByteArray> movingAuthorization;
......@@ -172,6 +173,7 @@ private:
std::string currentLogPath;
int32_t currentUserId = 0;
bool registeredForInternalPush = false;
bool pushConnectionEnabled = true;
ConnectiosManagerDelegate *delegate;
......
......@@ -17,10 +17,11 @@
#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
#define CONNECTION_BACKGROUND_KEEP_TIME 10000
class TLObject;
class TL_error;
......
......@@ -213,6 +213,8 @@
<receiver android:name=".WearReplyReceiver" android:enabled="true"/>
<receiver android:name=".ShareBroadcastReceiver" android:enabled="true"/>
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632dp" />
......
......@@ -77,7 +77,6 @@ public class SQLiteDatabase {
close();
}
private StackTraceElement[] temp;
public void beginTransaction() throws SQLiteException {
if (inTransaction) {
throw new SQLiteException("database already in transaction");
......
......@@ -20,6 +20,9 @@ import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
......@@ -37,8 +40,6 @@ 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 {
......@@ -47,6 +48,9 @@ public class ApplicationLoader extends Application {
private static boolean isCustomTheme;
private static final Object sync = new Object();
private static int serviceMessageColor;
private static int serviceSelectedMessageColor;
public static volatile Context applicationContext;
public static volatile Handler applicationHandler;
private static volatile boolean applicationInited = false;
......@@ -64,9 +68,27 @@ public class ApplicationLoader extends Application {
public static void reloadWallpaper() {
cachedWallpaper = null;
serviceMessageColor = 0;
ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().remove("serviceMessageColor").commit();
loadWallpaper();
}
private static void calcBackgroundColor() {
int result[] = AndroidUtilities.calcDrawableColor(cachedWallpaper);
serviceMessageColor = result[0];
serviceSelectedMessageColor = result[1];
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
preferences.edit().putInt("serviceMessageColor", serviceMessageColor).putInt("serviceSelectedMessageColor", serviceSelectedMessageColor).commit();
}
public static int getServiceMessageColor() {
return serviceMessageColor;
}
public static int getServiceSelectedMessageColor() {
return serviceSelectedMessageColor;
}
public static void loadWallpaper() {
if (cachedWallpaper != null) {
return;
......@@ -80,6 +102,8 @@ public class ApplicationLoader extends Application {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
int selectedBackground = preferences.getInt("selectedBackground", 1000001);
selectedColor = preferences.getInt("selectedColor", 0);
serviceMessageColor = preferences.getInt("serviceMessageColor", 0);
serviceSelectedMessageColor = preferences.getInt("serviceSelectedMessageColor", 0);
if (selectedColor == 0) {
if (selectedBackground == 1000001) {
cachedWallpaper = applicationContext.getResources().getDrawable(R.drawable.background_hd);
......@@ -104,6 +128,9 @@ public class ApplicationLoader extends Application {
}
cachedWallpaper = new ColorDrawable(selectedColor);
}
if (serviceMessageColor == 0) {
calcBackgroundColor();
}
}
}
});
......@@ -215,7 +242,7 @@ public class ApplicationLoader extends Application {
String configPath = getFilesDirFixed().toString();
try {
langCode = LocaleController.getLocaleString(LocaleController.getInstance().getSystemDefaultLocale());
langCode = LocaleController.getLocaleStringIso639();
deviceModel = Build.MANUFACTURER + Build.MODEL;
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
appVersion = pInfo.versionName + " (" + pInfo.versionCode + ")";
......@@ -239,8 +266,11 @@ public class ApplicationLoader extends Application {
systemVersion = "SDK Unknown";
}
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
boolean enablePushConnection = preferences.getBoolean("pushConnection", true);
MessagesController.getInstance();
ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId());
ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId(), enablePushConnection);
if (UserConfig.getCurrentUser() != null) {
MessagesController.getInstance().putUser(UserConfig.getCurrentUser(), true);
ConnectionsManager.getInstance().applyCountryPortNumber(UserConfig.getCurrentUser().phone);
......@@ -323,13 +353,18 @@ public class ApplicationLoader extends Application {
@Override
public void run() {
if (checkPlayServices()) {
if (UserConfig.pushString == null || UserConfig.pushString.length() == 0) {
if (UserConfig.pushString != null && UserConfig.pushString.length() != 0) {
FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString);
} else {
FileLog.d("tmessages", "GCM Registration not found.");
}
//if (UserConfig.pushString == null || UserConfig.pushString.length() == 0) {
Intent intent = new Intent(applicationContext, GcmRegistrationIntentService.class);
startService(intent);
} else {
FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString);
}
//} else {
// FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString);
//}
} else {
FileLog.d("tmessages", "No valid Google Play Services APK found.");
}
......
......@@ -16,6 +16,7 @@ public class AutoMessageHeardReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
long dialog_id = intent.getLongExtra("dialog_id", 0);
int max_id = intent.getIntExtra("max_id", 0);
if (dialog_id == 0 || max_id == 0) {
......
......@@ -18,6 +18,7 @@ public class AutoMessageReplyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput == null) {
return;
......@@ -31,7 +32,7 @@ public class AutoMessageReplyReceiver extends BroadcastReceiver {
if (dialog_id == 0 || max_id == 0) {
return;
}
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null);
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null, null);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
}
}
......@@ -10,8 +10,8 @@ package org.telegram.messenger;
public class BuildVars {
public static boolean DEBUG_VERSION = false;
public static int BUILD_VERSION = 767;
public static String BUILD_VERSION_STRING = "3.7";
public static int BUILD_VERSION = 787;
public static String BUILD_VERSION_STRING = "3.8";
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";
......
......@@ -27,6 +27,8 @@ public class ClearCacheService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
ApplicationLoader.postInitApplication();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
final int keepMedia = preferences.getInt("keep_media", 2);
if (keepMedia == 2) {
......
......@@ -173,7 +173,7 @@ public class ContactsController {
if (!updatingInviteText && (inviteText == null || time + 86400 < (int)(System.currentTimeMillis() / 1000))) {
updatingInviteText = true;
TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText();
req.lang_code = LocaleController.getLocaleString(LocaleController.getInstance().getSystemDefaultLocale());
req.lang_code = LocaleController.getLocaleStringIso639();
if (req.lang_code.length() == 0) {
req.lang_code = "en";
}
......@@ -1652,7 +1652,8 @@ public class ContactsController {
}
}*/
for (final TLRPC.User u : res.users) {
for (int a = 0; a < res.users.size(); a++) {
final TLRPC.User u = res.users.get(a);
Utilities.phoneBookQueue.postRunnable(new Runnable() {
@Override
public void run() {
......
......@@ -115,7 +115,7 @@ public class FileLoadOperation {
}
ext = FileLoader.getDocumentFileName(documentLocation);
int idx;
if (ext == null || (idx = ext.lastIndexOf(".")) == -1) {
if (ext == null || (idx = ext.lastIndexOf('.')) == -1) {
ext = "";
} else {
ext = ext.substring(idx);
......
......@@ -593,7 +593,9 @@ public class FileLoader {
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
if (message.media.webpage.photo != null) {
if (message.media.webpage.document != null) {
return getPathToAttach(message.media.webpage.document);
} else 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());
......@@ -601,8 +603,6 @@ public class FileLoader {
return getPathToAttach(sizeFull);
}
}
} else if (message.media.webpage.document != null) {
return getPathToAttach(message.media.webpage.document);
}
}
}
......@@ -667,7 +667,8 @@ public class FileLoader {
}
int lastSide = 0;
TLRPC.PhotoSize closestObject = null;
for (TLRPC.PhotoSize obj : sizes) {
for (int a = 0; a < sizes.size(); a++) {
TLRPC.PhotoSize obj = sizes.get(a);
if (obj == null) {
continue;
}
......@@ -691,7 +692,7 @@ public class FileLoader {
public static String getFileExtension(File file) {
String name = file.getName();
try {
return name.substring(name.lastIndexOf(".") + 1);
return name.substring(name.lastIndexOf('.') + 1);
} catch (Exception e) {
return "";
}
......@@ -714,7 +715,7 @@ public class FileLoader {
public static String getDocumentExtension(TLRPC.Document document) {
String fileName = getDocumentFileName(document);
int idx = fileName.lastIndexOf(".");
int idx = fileName.lastIndexOf('.');
String ext = null;
if (idx != -1) {
ext = fileName.substring(idx + 1);
......@@ -740,7 +741,7 @@ public class FileLoader {
if (docExt == null) {
docExt = getDocumentFileName(document);
int idx;
if (docExt == null || (idx = docExt.lastIndexOf(".")) == -1) {
if (docExt == null || (idx = docExt.lastIndexOf('.')) == -1) {
docExt = "";
} else {
docExt = docExt.substring(idx);
......
......@@ -138,8 +138,8 @@ public class FileLog {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + e + "\n");
StackTraceElement[] stack = e.getStackTrace();
for (StackTraceElement el : stack) {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + el + "\n");
for (int a = 0; a < stack.length; a++) {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + stack[a] + "\n");
}
getInstance().streamWriter.flush();
} catch (Exception e) {
......@@ -194,6 +194,9 @@ public class FileLog {
public static void cleanupLogs() {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
if (sdCard == null) {
return;
}
File dir = new File (sdCard.getAbsolutePath() + "/logs");
File[] files = dir.listFiles();
if (files != null) {
......
......@@ -46,6 +46,7 @@ public class GcmPushListenerService extends GcmListenerService {
FileLog.e("tmessages", e);
}
ConnectionsManager.onInternalPushReceived();
ConnectionsManager.getInstance().resumeNetworkMaybe();
}
});
......
......@@ -24,9 +24,15 @@ public class GcmRegistrationIntentService extends IntentService {
protected void onHandleIntent(Intent intent) {
try {
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(BuildVars.GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
final String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
FileLog.d("tmessages", "GCM Registration Token: " + token);
sendRegistrationToServer(token);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
ApplicationLoader.postInitApplication();
sendRegistrationToServer(token);
}
});
} catch (Exception e) {
FileLog.e("tmessages", e);
final int failCount = intent.getIntExtra("failCount", 0);
......
......@@ -1809,7 +1809,7 @@ public class ImageLoader {
key = document.dc_id + "_" + document.id;
String docExt = FileLoader.getDocumentFileName(document);
int idx;
if (docExt == null || (idx = docExt.lastIndexOf(".")) == -1) {
if (docExt == null || (idx = docExt.lastIndexOf('.')) == -1) {
docExt = "";
} else {
docExt = docExt.substring(idx);
......@@ -1946,21 +1946,12 @@ public class ImageLoader {
}
}
public void loadHttpFile(String url, String extension) {
public void loadHttpFile(String url, String defaultExt) {
if (url == null || url.length() == 0 || httpFileLoadTasksByKeys.containsKey(url)) {
return;
}
String ext = extension;
if (ext == null) {
int idx = url.lastIndexOf(".");
if (idx != -1) {
ext = url.substring(idx + 1);
}
if (ext == null || ext.length() == 0 || ext.length() > 4) {
ext = "jpg";
}
}
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + getHttpUrlExtension(url, extension));
String ext = getHttpUrlExtension(url, defaultExt);
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + ext);
file.delete();
HttpFileTask task = new HttpFileTask(url, file, ext);
......@@ -2276,7 +2267,7 @@ public class ImageLoader {
public static String getHttpUrlExtension(String url, String defaultExt) {
String ext = null;
int idx = url.lastIndexOf(".");
int idx = url.lastIndexOf('.');
if (idx != -1) {
ext = url.substring(idx + 1);
}
......
......@@ -309,7 +309,31 @@ public class LocaleController {
return systemDefaultLocale;
}
public static String getLocaleString(Locale locale) {
private String getLocaleString(Locale locale) {
if (locale == null) {
return "en";
}
String languageCode = locale.getLanguage();
String countryCode = locale.getCountry();
String variantCode = locale.getVariant();
if (languageCode.length() == 0 && countryCode.length() == 0) {
return "en";
}
StringBuilder result = new StringBuilder(11);
result.append(languageCode);
if (countryCode.length() > 0 || variantCode.length() > 0) {
result.append('_');
}
result.append(countryCode);
if (variantCode.length() > 0) {
result.append('_');
}
result.append(variantCode);
return result.toString();
}
public static String getLocaleStringIso639() {
Locale locale = getInstance().getSystemDefaultLocale();
if (locale == null) {
return "en";
}
......@@ -583,7 +607,11 @@ public class LocaleController {
private String getStringInternal(String key, int res) {
String value = localeValues.get(key);
if (value == null) {
value = ApplicationLoader.applicationContext.getString(res);
try {
value = ApplicationLoader.applicationContext.getString(res);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
if (value == null) {
value = "LOC_ERR:" + key;
......
......@@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
public class NativeLoader {
private final static int LIB_VERSION = 20;
private final static int LIB_VERSION = 21;
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";
......
......@@ -70,6 +70,7 @@ public class NotificationCenter {
public static final int needReloadRecentDialogsSearch = totalEvents++;
public static final int locationPermissionGranted = totalEvents++;
public static final int peerSettingsDidLoaded = totalEvents++;
public static final int wasUnableToFindCurrentLocation = totalEvents++;
public static final int httpFileDidLoaded = totalEvents++;
public static final int httpFileDidFailedLoad = totalEvents++;
......@@ -115,6 +116,8 @@ public class NotificationCenter {
private int broadcasting = 0;
private boolean animationInProgress;
private int[] allowedNotifications;
public interface NotificationCenterDelegate {
void didReceivedNotification(int id, Object... args);
}
......@@ -145,6 +148,10 @@ public class NotificationCenter {
return localInstance;
}
public void setAllowedNotificationsDutingAnimation(int notifications[]) {
allowedNotifications = notifications;
}
public void setAnimationInProgress(boolean value) {
animationInProgress = value;
if (!animationInProgress && !delayedPosts.isEmpty()) {
......@@ -157,8 +164,13 @@ public class NotificationCenter {
public void postNotificationName(int id, Object... args) {
boolean allowDuringAnimation = false;
if (id == chatInfoDidLoaded || id == dialogsNeedReload || id == closeChats || id == messagesDidLoaded || id == mediaCountDidLoaded || id == mediaDidLoaded || id == botInfoDidLoaded || id == botKeyboardDidLoaded) {
allowDuringAnimation = true;
if (allowedNotifications != null) {
for (int a = 0; a < allowedNotifications.length; a++) {
if (allowedNotifications[a] == id) {
allowDuringAnimation = true;
break;
}
}
}
postNotificationNameInternal(id, allowDuringAnimation, args);
}
......
......@@ -380,6 +380,7 @@ public class NotificationsController {
int oldCount = popupArray.size();
HashMap<Long, Boolean> settingsCache = new HashMap<>();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
boolean allowPinned = preferences.getBoolean("PinnedMessages", true);
int popup = 0;
for (int a = 0; a < messageObjects.size(); a++) {
......@@ -398,6 +399,9 @@ public class NotificationsController {
continue;
}
if (messageObject.messageOwner.mentioned) {
if (!allowPinned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) {
continue;
}
dialog_id = messageObject.messageOwner.from_id;
}
if (isPersonalMessage(messageObject)) {
......@@ -683,7 +687,7 @@ public class NotificationsController {
int chat_id = messageObject.messageOwner.to_id.chat_id != 0 ? messageObject.messageOwner.to_id.chat_id : messageObject.messageOwner.to_id.channel_id;
int from_id = messageObject.messageOwner.to_id.user_id;
if (from_id == 0) {
if (messageObject.isFromUser()) {
if (messageObject.isFromUser() || messageObject.getId() < 0) {
from_id = messageObject.messageOwner.from_id;
} else {
from_id = -chat_id;
......@@ -725,7 +729,7 @@ public class NotificationsController {
}
String msg = null;
if ((int)dialog_id == 0 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) {
if ((int) dialog_id == 0 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) {
msg = LocaleController.getString("YouHaveNewMessage", R.string.YouHaveNewMessage);
} else {
if (chat_id == 0 && from_id != 0) {
......@@ -787,12 +791,6 @@ public class NotificationsController {
}
if (singleUserId != 0) {
if (messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) {
TLRPC.User user = MessagesController.getInstance().getUser(singleUserId);
if (user != null) {
name = UserObject.getUserName(user);
} else {
name = "";
}
msg = LocaleController.formatString("ChannelAddedByNotification", R.string.ChannelAddedByNotification, name, chat.title);
} else {
if (singleUserId == UserConfig.getClientUserId()) {
......@@ -1513,7 +1511,7 @@ public class NotificationsController {
if (silent != 1 && !notifyDisabled) {
if (ApplicationLoader.mainInterfacePaused || inAppPreview) {
if (lastMessage.length() > 100) {
lastMessage = lastMessage.substring(0, 100).replace("\n", " ").trim() + "...";
lastMessage = lastMessage.substring(0, 100).replace('\n', ' ').trim() + "...";
}
mBuilder.setTicker(lastMessage);
}
......
......@@ -849,6 +849,36 @@ public class SecretChatHelper {
});
}
private void applyPeerLayer(final TLRPC.EncryptedChat chat, int newPeerLayer) {
int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer);
if (newPeerLayer <= currentPeerLayer) {
return;
}
if (chat.key_hash.length == 16 && currentPeerLayer >= 46) {
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);
chat.key_hash = key_hash;
MessagesStorage.getInstance().updateEncryptedChat(chat);
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
}
chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, newPeerLayer);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
if (currentPeerLayer < CURRENT_SECRET_CHAT_LAYER) {
sendNotifyLayerMessage(chat, null);
}
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, chat);
}
});
}
public TLRPC.Message processDecryptedObject(final TLRPC.EncryptedChat chat, final TLRPC.EncryptedFile file, int date, long random_id, TLObject object, boolean new_key_used) {
if (object != null) {
int from_id = chat.admin_id;
......@@ -1156,30 +1186,7 @@ public class SecretChatHelper {
MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 1, serviceMessage.action.random_ids);
}
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer);
if (chat.key_hash.length == 16 && currentPeerLayer >= 46) {
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);
chat.key_hash = key_hash;
MessagesStorage.getInstance().updateEncryptedChat(chat);
} catch (Throwable e) {
FileLog.e("tmessages", e);
}
}
chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
if (currentPeerLayer < CURRENT_SECRET_CHAT_LAYER) {
sendNotifyLayerMessage(chat, null);
}
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, chat);
}
});
applyPeerLayer(chat, serviceMessage.action.layer);
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionRequestKey) {
if (chat.exchange_id != 0) {
if (chat.exchange_id > serviceMessage.action.exchange_id) {
......@@ -1374,6 +1381,7 @@ public class SecretChatHelper {
for (int a = 0; a < holes.size(); a++) {
TL_decryptedMessageHolder holder = holes.get(a);
if (holder.layer.out_seq_no == chat.seq_in || chat.seq_in == holder.layer.out_seq_no - 2) {
applyPeerLayer(chat, holder.layer.layer);
chat.seq_in = holder.layer.out_seq_no;
holes.remove(a);
a--;
......@@ -1493,6 +1501,7 @@ public class SecretChatHelper {
arr.add(holder);
return null;
}
applyPeerLayer(chat, layer.layer);
chat.seq_in = layer.out_seq_no;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
object = layer.message;
......
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package org.telegram.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class ShareBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String url = intent.getDataString();
if (url != null) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
Intent chooserIntent = Intent.createChooser(shareIntent, LocaleController.getString("ShareLink", R.string.ShareLink));
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(chooserIntent);
}
}
}
......@@ -47,7 +47,7 @@ public class Utilities {
public native static void loadBitmap(String path, Bitmap bitmap, int scale, int width, int height, int stride);
public native static int pinBitmap(Bitmap bitmap);
public native static int unpinBitmap(Bitmap bitmap);
public native static void unpinBitmap(Bitmap bitmap);
public native static void blurBitmap(Object bitmap, int radius, int unpin, int width, int height, int stride);
public native static void calcCDT(ByteBuffer hsvBuffer, int width, int height, ByteBuffer buffer);
public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin);
......@@ -255,8 +255,8 @@ public class Utilities {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(md5.getBytes());
StringBuilder sb = new StringBuilder();
for (byte anArray : array) {
sb.append(Integer.toHexString((anArray & 0xFF) | 0x100).substring(1, 3));
for (int a = 0; a < array.length; a++) {
sb.append(Integer.toHexString((array[a] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
......
......@@ -18,6 +18,7 @@ public class WearReplyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput == null) {
return;
......@@ -31,7 +32,7 @@ public class WearReplyReceiver extends BroadcastReceiver {
if (dialog_id == 0 || max_id == 0) {
return;
}
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null);
SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null, null);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
}
}
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package org.telegram.messenger.browser;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MediaController;
import org.telegram.messenger.R;
import org.telegram.messenger.ShareBroadcastReceiver;
import org.telegram.messenger.support.customtabs.CustomTabsCallback;
import org.telegram.messenger.support.customtabs.CustomTabsClient;
import org.telegram.messenger.support.customtabs.CustomTabsIntent;
import org.telegram.messenger.support.customtabs.CustomTabsServiceConnection;
import org.telegram.messenger.support.customtabs.CustomTabsSession;
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.ui.ActionBar.Theme;
import org.telegram.ui.LaunchActivity;
import java.lang.ref.WeakReference;
public class Browser {
private static WeakReference<CustomTabsSession> customTabsCurrentSession;
private static CustomTabsSession customTabsSession;
private static CustomTabsClient customTabsClient;
private static CustomTabsServiceConnection customTabsServiceConnection;
private static String customTabsPackageToBind;
private static WeakReference<Activity> currentCustomTabsActivity;
private static CustomTabsSession getCurrentSession() {
return customTabsCurrentSession == null ? null : customTabsCurrentSession.get();
}
private static void setCurrentSession(CustomTabsSession session) {
customTabsCurrentSession = new WeakReference<>(session);
}
private static CustomTabsSession getSession() {
if (customTabsClient == null) {
customTabsSession = null;
} else if (customTabsSession == null) {
customTabsSession = customTabsClient.newSession(new NavigationCallback());
setCurrentSession(customTabsSession);
}
return customTabsSession;
}
public static void bindCustomTabsService(Activity activity) {
if (Build.VERSION.SDK_INT < 15) {
return;
}
Activity currentActivity = currentCustomTabsActivity == null ? null : currentCustomTabsActivity.get();
if (currentActivity != null && currentActivity != activity) {
unbindCustomTabsService(currentActivity);
}
if (customTabsClient != null) {
return;
}
currentCustomTabsActivity = new WeakReference<>(activity);
try {
if (TextUtils.isEmpty(customTabsPackageToBind)) {
customTabsPackageToBind = CustomTabsHelper.getPackageNameToUse(activity);
if (customTabsPackageToBind == null) {
return;
}
}
customTabsServiceConnection = new ServiceConnection(new ServiceConnectionCallback() {
@Override
public void onServiceConnected(CustomTabsClient client) {
customTabsClient = client;
if (customTabsClient != null) {
customTabsClient.warmup(0);
}
}
@Override
public void onServiceDisconnected() {
customTabsClient = null;
}
});
if (!CustomTabsClient.bindCustomTabsService(activity, customTabsPackageToBind, customTabsServiceConnection)) {
customTabsServiceConnection = null;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public static void unbindCustomTabsService(Activity activity) {
if (Build.VERSION.SDK_INT < 15 || customTabsServiceConnection == null) {
return;
}
Activity currentActivity = currentCustomTabsActivity == null ? null : currentCustomTabsActivity.get();
if (currentActivity == activity) {
currentCustomTabsActivity.clear();
}
try {
activity.unbindService(customTabsServiceConnection);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
customTabsClient = null;
customTabsSession = null;
}
private static class NavigationCallback extends CustomTabsCallback {
@Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {
FileLog.e("tmessages", "code = " + navigationEvent + " extras " + extras);
}
}
public static void openUrl(Context context, String url) {
openUrl(context, Uri.parse(url), true);
}
public static void openUrl(Context context, Uri uri) {
openUrl(context, uri, true);
}
public static void openUrl(Context context, String url, boolean allowCustom) {
if (context == null || url == null) {
return;
}
openUrl(context, Uri.parse(url), allowCustom);
}
public static void openUrl(Context context, Uri uri, boolean allowCustom) {
if (context == null || uri == null) {
return;
}
try {
boolean internalUri = isInternalUri(uri);
if (Build.VERSION.SDK_INT >= 15 && allowCustom && MediaController.getInstance().canCustomTabs() && !internalUri) {
Intent share = new Intent(ApplicationLoader.applicationContext, ShareBroadcastReceiver.class);
share.setAction(Intent.ACTION_SEND);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getSession());
builder.setToolbarColor(Theme.ACTION_BAR_COLOR);
builder.setShowTitle(true);
builder.setActionButton(BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha), LocaleController.getString("ShareFile", R.string.ShareFile), PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, share, 0), false);
CustomTabsIntent intent = builder.build();
intent.launchUrl((Activity) context, uri);
} else {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (internalUri) {
ComponentName componentName = new ComponentName(context.getPackageName(), LaunchActivity.class.getName());
intent.setComponent(componentName);
}
intent.putExtra(android.provider.Browser.EXTRA_APPLICATION_ID, context.getPackageName());
context.startActivity(intent);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public static boolean isInternalUrl(String url) {
return isInternalUri(Uri.parse(url));
}
public static boolean isInternalUri(Uri uri) {
String host = uri.getHost();
host = host != null ? host.toLowerCase() : "";
return "tg".equals(uri.getScheme()) || "telegram.me".equals(host) || "telegram.dog".equals(host);
}
}
......@@ -144,12 +144,14 @@ public class SharedMediaQuery {
if (message == null) {
return -1;
}
if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
return MEDIA_PHOTOVIDEO;
} else if (MessageObject.isVoiceMessage(message)) {
return MEDIA_AUDIO;
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
if (MessageObject.isStickerMessage(message)) {
if (MessageObject.isVoiceMessage(message)) {
return MEDIA_AUDIO;
} else if (MessageObject.isVideoMessage(message)) {
return MEDIA_PHOTOVIDEO;
} else if (MessageObject.isStickerMessage(message)) {
return -1;
} else if (MessageObject.isMusicMessage(message)) {
return MEDIA_MUSIC;
......
......@@ -8,11 +8,7 @@
package org.telegram.messenger.query;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Message;
import android.widget.Toast;
import org.telegram.SQLite.SQLiteCursor;
......@@ -29,8 +25,6 @@ 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.BaseFragment;
import org.telegram.ui.Components.StickersAlert;
import java.util.ArrayList;
import java.util.Collections;
......@@ -85,6 +79,14 @@ public class StickersQuery {
return document;
}
public static TLRPC.TL_messages_stickerSet getStickerSetByName(String name) {
return stickerSetsByName.get(name);
}
public static TLRPC.TL_messages_stickerSet getStickerSetById(Long id) {
return stickerSetsById.get(id);
}
public static HashMap<String, ArrayList<TLRPC.Document>> getAllStickers() {
return allStickers;
}
......@@ -441,100 +443,6 @@ public class StickersQuery {
});
}
public static void loadStickers(final BaseFragment fragment, final TLRPC.InputStickerSet stickerSet) {
if (fragment == null || stickerSet == null) {
return;
}
final ProgressDialog progressDialog = new ProgressDialog(fragment.getParentActivity());
progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
TLRPC.TL_messages_getStickerSet req = new TLRPC.TL_messages_getStickerSet();
req.stickerset = stickerSet;
final int reqId = ConnectionsManager.getInstance().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("tmessages", e);
}
if (fragment.getParentActivity() != null && !fragment.getParentActivity().isFinishing()) {
if (error == null) {
final TLRPC.TL_messages_stickerSet res = (TLRPC.TL_messages_stickerSet) response;
StickersAlert alert = new StickersAlert(fragment.getParentActivity(), res);
if (res.set == null || !StickersQuery.isStickerPackInstalled(res.set.id)) {
alert.setButton(AlertDialog.BUTTON_POSITIVE, LocaleController.getString("AddStickers", R.string.AddStickers), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet();
req.stickerset = stickerSet;
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, final TLRPC.TL_error error) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
if (fragment.getParentActivity() != null) {
if (error == null) {
Toast.makeText(fragment.getParentActivity(), LocaleController.getString("AddStickersInstalled", R.string.AddStickersInstalled), Toast.LENGTH_SHORT).show();
} else {
if (error.text.equals("STICKERSETS_TOO_MUCH")) {
Toast.makeText(fragment.getParentActivity(), LocaleController.getString("TooMuchStickersets", R.string.TooMuchStickersets), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(fragment.getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show();
}
}
}
loadStickers(false, true);
}
});
}
});
}
});
} else {
alert.setButton(AlertDialog.BUTTON_NEUTRAL, LocaleController.getString("StickersRemove", R.string.StickersRemove), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
removeStickersSet(fragment.getParentActivity(), res.set, 0);
}
});
}
alert.setButton(AlertDialog.BUTTON_NEGATIVE, LocaleController.getString("Close", R.string.Close), (Message) null);
fragment.setVisibleDialog(alert);
alert.show();
} else {
Toast.makeText(fragment.getParentActivity(), LocaleController.getString("AddStickersNotFound", R.string.AddStickersNotFound), Toast.LENGTH_SHORT).show();
}
}
}
});
}
});
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ConnectionsManager.getInstance().cancelRequest(reqId, true);
try {
dialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
fragment.setVisibleDialog(progressDialog);
progressDialog.show();
}
public static void removeStickersSet(final Context context, TLRPC.StickerSet stickerSet, int hide) {
TLRPC.TL_inputStickerSetID stickerSetID = new TLRPC.TL_inputStickerSetID();
stickerSetID.access_hash = stickerSet.access_hash;
......
/*
* Copyright (C) 2015 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.support.customtabs;
import android.os.Bundle;
/**
* A callback class for custom tabs client to get messages regarding events in their custom tabs.
*/
public class CustomTabsCallback {
public static final int NAVIGATION_STARTED = 1;
public static final int NAVIGATION_FINISHED = 2;
public static final int NAVIGATION_FAILED = 3;
public static final int NAVIGATION_ABORTED = 4;
public static final int TAB_SHOWN = 5;
public static final int TAB_HIDDEN = 6;
public CustomTabsCallback() {
}
public void onNavigationEvent(int navigationEvent, Bundle extras) {
}
public void extraCallback(String callbackName, Bundle args) {
}
}
/*
* Copyright (C) 2015 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.support.customtabs;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
public class CustomTabsClient {
private final ICustomTabsService mService;
private final ComponentName mServiceComponentName;
CustomTabsClient(ICustomTabsService service, ComponentName componentName) {
this.mService = service;
this.mServiceComponentName = componentName;
}
public static boolean bindCustomTabsService(Context context, String packageName, CustomTabsServiceConnection connection) {
Intent intent = new Intent("android.support.customtabs.action.CustomTabsService");
if (!TextUtils.isEmpty(packageName)) {
intent.setPackage(packageName);
}
return context.bindService(intent, connection, 33);
}
public boolean warmup(long flags) {
try {
return this.mService.warmup(flags);
} catch (RemoteException var4) {
return false;
}
}
public CustomTabsSession newSession(final CustomTabsCallback callback) {
ICustomTabsCallback.Stub wrapper = new ICustomTabsCallback.Stub() {
public void onNavigationEvent(int navigationEvent, Bundle extras) {
if (callback != null) {
callback.onNavigationEvent(navigationEvent, extras);
}
}
public void extraCallback(String callbackName, Bundle args) throws RemoteException {
if (callback != null) {
callback.extraCallback(callbackName, args);
}
}
};
try {
if (!this.mService.newSession(wrapper)) {
return null;
}
} catch (RemoteException var4) {
return null;
}
return new CustomTabsSession(this.mService, wrapper, this.mServiceComponentName);
}
public Bundle extraCommand(String commandName, Bundle args) {
try {
return this.mService.extraCommand(commandName, args);
} catch (RemoteException var4) {
return null;
}
}
}
/*
* Copyright (C) 2015 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.support.customtabs;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.support.v4.util.ArrayMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
public abstract class CustomTabsService extends Service {
public static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
public static final String KEY_URL = "android.support.customtabs.otherurls.URL";
private final Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap();
private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() {
public boolean warmup(long flags) {
return CustomTabsService.this.warmup(flags);
}
public boolean newSession(ICustomTabsCallback callback) {
final CustomTabsSessionToken sessionToken = new CustomTabsSessionToken(callback);
try {
DeathRecipient e = new DeathRecipient() {
public void binderDied() {
CustomTabsService.this.cleanUpSession(sessionToken);
}
};
synchronized (CustomTabsService.this.mDeathRecipientMap) {
callback.asBinder().linkToDeath(e, 0);
CustomTabsService.this.mDeathRecipientMap.put(callback.asBinder(), e);
}
return CustomTabsService.this.newSession(sessionToken);
} catch (RemoteException var7) {
return false;
}
}
public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url, Bundle extras, List<Bundle> otherLikelyBundles) {
return CustomTabsService.this.mayLaunchUrl(new CustomTabsSessionToken(callback), url, extras, otherLikelyBundles);
}
public Bundle extraCommand(String commandName, Bundle args) {
return CustomTabsService.this.extraCommand(commandName, args);
}
public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) {
return CustomTabsService.this.updateVisuals(new CustomTabsSessionToken(callback), bundle);
}
};
public CustomTabsService() {
}
public IBinder onBind(Intent intent) {
return this.mBinder;
}
protected boolean cleanUpSession(CustomTabsSessionToken sessionToken) {
try {
Map e = this.mDeathRecipientMap;
synchronized (this.mDeathRecipientMap) {
IBinder binder = sessionToken.getCallbackBinder();
DeathRecipient deathRecipient = this.mDeathRecipientMap.get(binder);
binder.unlinkToDeath(deathRecipient, 0);
this.mDeathRecipientMap.remove(binder);
return true;
}
} catch (NoSuchElementException var7) {
return false;
}
}
protected abstract boolean warmup(long var1);
protected abstract boolean newSession(CustomTabsSessionToken var1);
protected abstract boolean mayLaunchUrl(CustomTabsSessionToken var1, Uri var2, Bundle var3, List<Bundle> var4);
protected abstract Bundle extraCommand(String var1, Bundle var2);
protected abstract boolean updateVisuals(CustomTabsSessionToken var1, Bundle var2);
}
/*
* Copyright (C) 2015 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.support.customtabs;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
public abstract class CustomTabsServiceConnection implements ServiceConnection {
public CustomTabsServiceConnection() {
}
public final void onServiceConnected(final ComponentName name, IBinder service) {
this.onCustomTabsServiceConnected(name, new CustomTabsClient(ICustomTabsService.Stub.asInterface(service), name) {
});
}
public abstract void onCustomTabsServiceConnected(ComponentName var1, CustomTabsClient var2);
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.support.customtabsclient.shared;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class KeepAliveService extends Service {
private static final Binder sBinder = new Binder();
@Override
public IBinder onBind(Intent intent) {
return sBinder;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment