Commit 6154c891 authored by DrKLO's avatar DrKLO

Update to 3.6.1

parent 2114024a
......@@ -83,7 +83,7 @@ android {
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionCode 719
versionName "3.4.2"
versionCode 755
versionName "3.6.1"
}
}
......@@ -235,7 +235,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := tmessages.17
LOCAL_MODULE := tmessages.19
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
......
......@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <time.h>
#include <opusfile.h>
#include <math.h>
#include "utils.h"
typedef struct {
......@@ -663,6 +664,156 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env
result = error == OPUS_OK;
}
if (pathStr != 0) {
(*env)->ReleaseStringUTFChars(env, path, pathStr);
}
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;
bytes += bitOffset / 8;
bitOffset %= 8;
*((int32_t *) bytes) |= (value << bitOffset);
}
JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JNIEnv *env, jclass class, jshortArray array, jint length) {
jshort *sampleBuffer = (*env)->GetShortArrayElements(env, array, 0);
jbyteArray result = 0;
int32_t resultSamples = 100;
uint16_t *samples = malloc(100 * 2);
uint64_t sampleIndex = 0;
uint16_t peakSample = 0;
int32_t sampleRate = (int32_t) max(1, length / resultSamples);
int index = 0;
for (int i = 0; i < length; i++) {
uint16_t sample = (uint16_t) abs(sampleBuffer[i]);
if (sample > peakSample) {
peakSample = sample;
}
if (sampleIndex++ % sampleRate == 0) {
if (index < resultSamples) {
samples[index++] = peakSample;
}
peakSample = 0;
}
}
int64_t sumSamples = 0;
for (int i = 0; i < resultSamples; i++) {
sumSamples += samples[i];
}
uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples);
if (peak < 2500) {
peak = 2500;
}
for (int i = 0; i < resultSamples; i++) {
uint16_t sample = (uint16_t) ((int64_t) samples[i]);
if (sample > peak) {
samples[i] = peak;
}
}
(*env)->ReleaseShortArrayElements(env, array, sampleBuffer, 0);
int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1);
result = (*env)->NewByteArray(env, bitstreamLength);
jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL);
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);
}
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
free(samples);
return result;
}
int16_t *sampleBuffer = NULL;
JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) {
const char *pathStr = (*env)->GetStringUTFChars(env, path, 0);
jbyteArray result = 0;
int error = OPUS_OK;
OggOpusFile *opusFile = op_open_file(pathStr, &error);
if (opusFile != NULL && error == OPUS_OK) {
int64_t totalSamples = op_pcm_total(opusFile, -1);
int32_t resultSamples = 100;
int32_t sampleRate = (int32_t) max(1, totalSamples / resultSamples);
uint16_t *samples = malloc(100 * 2);
int bufferSize = 1024 * 128;
if (sampleBuffer == NULL) {
sampleBuffer = malloc(bufferSize);
}
uint64_t sampleIndex = 0;
uint16_t peakSample = 0;
int index = 0;
while (1) {
int readSamples = op_read(opusFile, sampleBuffer, bufferSize / 2, NULL);
for (int i = 0; i < readSamples; i++) {
uint16_t sample = (uint16_t) abs(sampleBuffer[i]);
if (sample > peakSample) {
peakSample = sample;
}
if (sampleIndex++ % sampleRate == 0) {
if (index < resultSamples) {
samples[index++] = peakSample;
}
peakSample = 0;
}
}
if (readSamples == 0) {
break;
}
}
int64_t sumSamples = 0;
for (int i = 0; i < resultSamples; i++) {
sumSamples += samples[i];
}
uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples);
if (peak < 2500) {
peak = 2500;
}
for (int i = 0; i < resultSamples; i++) {
uint16_t sample = (uint16_t) ((int64_t) samples[i]);
if (sample > peak) {
samples[i] = peak;
}
}
//free(sampleBuffer);
op_free(opusFile);
int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1);
result = (*env)->NewByteArray(env, bitstreamLength);
jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL);
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);
}
(*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT);
free(samples);
}
if (pathStr != 0) {
(*env)->ReleaseStringUTFChars(env, path, pathStr);
}
......
......@@ -59,3 +59,16 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en
(*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0);
}
JNIEXPORT jstring Java_org_telegram_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
static char buf[1000];
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
int result = readlink(fileName, buf, 999);
jstring value = 0;
if (result != -1) {
buf[result] = '\0';
value = (*env)->NewStringUTF(env, buf);
}
(*env)->ReleaseStringUTFChars(env, path, fileName);
return value;
}
......@@ -6,6 +6,8 @@
* Copyright Nikolai Kudashov, 2015.
*/
#include <openssl/rand.h>
#include <stdlib.h>
#include "Connection.h"
#include "ConnectionsManager.h"
#include "BuffersStorage.h"
......@@ -55,6 +57,8 @@ void Connection::suspendConnection() {
}
void Connection::onReceivedData(NativeByteBuffer *buffer) {
//AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum);
failedConnectionCount = 0;
NativeByteBuffer *parseLaterBuffer = nullptr;
......@@ -305,12 +309,47 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
bufferLen += 4;
}
if (!firstPacketSent) {
bufferLen++;
bufferLen += 64;
}
NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(bufferLen);
uint8_t *bytes = buffer->bytes();
if (!firstPacketSent) {
buffer->writeByte(0xef);
buffer->position(64);
static uint8_t temp[64];
while (true) {
RAND_bytes(bytes, 64);
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;
break;
}
}
/*for (int a = 0; a < 48; a++) {
temp[a] = bytes[55 - a];
}
encryptNum = decryptNum = 0;
memset(encryptCount, 0, 16);
memset(decryptCount, 0, 16);
if (AES_set_encrypt_key(bytes + 8, 256, &encryptKey) < 0) {
DEBUG_E("unable to set encryptKey");
exit(1);
}
memcpy(encryptIv, bytes + 40, 16);
if (AES_set_encrypt_key(temp, 256, &decryptKey) < 0) {
DEBUG_E("unable to set decryptKey");
exit(1);
}
memcpy(decryptIv, temp + 32, 16);
AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum);
memcpy(bytes + 56, temp + 56, 8);*/
firstPacketSent = true;
}
if (packetLength < 0x7f) {
......@@ -318,17 +357,22 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
packetLength |= (1 << 7);
}
buffer->writeByte((uint8_t) packetLength);
bytes += (buffer->limit() - 1);
//AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum);
} else {
packetLength = (packetLength << 8) + 0x7f;
if (reportAck) {
packetLength |= (1 << 7);
}
buffer->writeInt32(packetLength);
bytes += (buffer->limit() - 4);
//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);
writeBuffer(buff);
}
......
......@@ -12,6 +12,7 @@
#include <pthread.h>
#include <vector>
#include <string>
#include <openssl/aes.h>
#include "ConnectionSession.h"
#include "ConnectionSocket.h"
#include "Defines.h"
......@@ -68,6 +69,16 @@ private:
uint32_t willRetryConnectCount = 5;
Timer *reconnectTimer;
AES_KEY encryptKey;
uint8_t encryptIv[16];
uint32_t encryptNum;
uint8_t encryptCount[16];
AES_KEY decryptKey;
uint8_t decryptIv[16];
uint32_t decryptNum;
uint8_t decryptCount[16];
friend class ConnectionsManager;
};
......
......@@ -946,6 +946,7 @@ void TL_config::readParams(NativeByteBuffer *stream, bool &error) {
push_chat_period_ms = stream->readInt32(&error);
push_chat_limit = stream->readInt32(&error);
saved_gifs_limit = stream->readInt32(&error);
edit_time_limit = stream->readInt32(&error);
magic = stream->readUint32(&error);
if (magic != 0x1cb5c415) {
error = true;
......@@ -987,6 +988,7 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(push_chat_period_ms);
stream->writeInt32(push_chat_limit);
stream->writeInt32(saved_gifs_limit);
stream->writeInt32(edit_time_limit);
stream->writeInt32(0x1cb5c415);
count = (uint32_t) disabled_features.size();
stream->writeInt32(count);
......
......@@ -657,7 +657,7 @@ public:
class TL_config : public TLObject {
public:
static const uint32_t constructor = 0x6bbc5f8;
static const uint32_t constructor = 0x317ceef4;
int32_t date;
int32_t expires;
......@@ -677,6 +677,7 @@ public:
int32_t push_chat_period_ms;
int32_t push_chat_limit;
int32_t saved_gifs_limit;
int32_t edit_time_limit;
std::vector<std::unique_ptr<TL_disabledFeature>> disabled_features;
static TL_config *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
......
......@@ -129,18 +129,28 @@
android:windowSoftInputMode="adjustResize|stateHidden">
</activity>
<receiver android:name=".AutoMessageHeardReceiver">
<receiver
android:name=".AutoMessageHeardReceiver"
android:exported="false">
<intent-filter>
<action android:name="org.telegram.messenger.ACTION_MESSAGE_HEARD"/>
</intent-filter>
</receiver>
<receiver android:name=".AutoMessageReplyReceiver">
<receiver
android:name=".AutoMessageReplyReceiver"
android:exported="false">
<intent-filter>
<action android:name="org.telegram.messenger.ACTION_MESSAGE_REPLY"/>
</intent-filter>
</receiver>
<receiver android:name=".CallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<receiver android:name=".SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
......
......@@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.Browser;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.Spannable;
......@@ -409,6 +411,29 @@ public class AndroidUtilities {
}
}
public static void openUrl(Context context, String url) {
if (context == null || url == null) {
return;
}
openUrl(context, Uri.parse(url));
}
public static void openUrl(Context context, Uri uri) {
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);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
context.startActivity(intent);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public static int getPhotoSize() {
if (photoSize == null) {
if (Build.VERSION.SDK_INT >= 16) {
......@@ -1057,4 +1082,11 @@ public class AndroidUtilities {
}
return true;
}
public static byte[] calcAuthKeyHash(byte[] auth_key) {
byte[] sha1 = Utilities.computeSHA1(auth_key);
byte[] key_hash = new byte[16];
System.arraycopy(sha1, 0, key_hash, 0, 16);
return key_hash;
}
}
......@@ -325,6 +325,8 @@ public class ApplicationLoader extends Application {
FileLog.d("tmessages", "GCM Registration not found.");
Intent intent = new Intent(applicationContext, GcmRegistrationIntentService.class);
startService(intent);
} else {
FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString);
}
} else {
FileLog.d("tmessages", "No valid Google Play Services APK found.");
......
......@@ -3,14 +3,15 @@
* 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-2015.
* Copyright Nikolai Kudashov, 2013-2016.
*/
package org.telegram.messenger;
public class BuildVars {
public static boolean DEBUG_VERSION = false;
public static int BUILD_VERSION = 719;
public static int BUILD_VERSION = 753;
public static String BUILD_VERSION_STRING = "3.6";
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";
......
/*
* 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 CallReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
/*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);
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);*/
}
}
......@@ -48,6 +48,9 @@ public class ClearCacheService extends IntentService {
for (int b = 0; b < array.length; b++) {
File f = array[b];
if (f.isFile()) {
if (f.getName().equals(".nomedia")) {
continue;
}
if (Build.VERSION.SDK_INT >= 21) {
try {
StructStat stat = Os.stat(f.getPath());
......
......@@ -56,7 +56,9 @@ public class ContactsController {
private int loadingDeleteInfo = 0;
private int deleteAccountTTL;
private int loadingLastSeenInfo = 0;
private int loadingGroupInfo = 0;
private ArrayList<TLRPC.PrivacyRule> privacyRules = null;
private ArrayList<TLRPC.PrivacyRule> groupPrivacyRules = null;
public static class Contact {
public int id;
......@@ -160,6 +162,7 @@ public class ContactsController {
loadingDeleteInfo = 0;
deleteAccountTTL = 0;
loadingLastSeenInfo = 0;
loadingGroupInfo = 0;
privacyRules = null;
}
......@@ -177,8 +180,8 @@ public class ContactsController {
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response;
if (response != null) {
final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText) response;
if (res.message.length() != 0) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
......@@ -1859,6 +1862,30 @@ public class ContactsController {
}
});
}
if (loadingGroupInfo == 0) {
loadingGroupInfo = 1;
TLRPC.TL_account_getPrivacy req = new TLRPC.TL_account_getPrivacy();
req.key = new TLRPC.TL_inputPrivacyKeyChatInvite();
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() {
if (error == null) {
TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response;
MessagesController.getInstance().putUsers(rules.users, false);
groupPrivacyRules = rules.rules;
loadingGroupInfo = 2;
} else {
loadingGroupInfo = 0;
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
}
});
}
});
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
}
......@@ -1878,12 +1905,24 @@ public class ContactsController {
return loadingLastSeenInfo != 2;
}
public ArrayList<TLRPC.PrivacyRule> getPrivacyRules() {
public boolean getLoadingGroupInfo() {
return loadingGroupInfo != 2;
}
public ArrayList<TLRPC.PrivacyRule> getPrivacyRules(boolean isGroup) {
if (isGroup) {
return groupPrivacyRules;
} else {
return privacyRules;
}
}
public void setPrivacyRules(ArrayList<TLRPC.PrivacyRule> rules) {
public void setPrivacyRules(ArrayList<TLRPC.PrivacyRule> rules, boolean isGroup) {
if (isGroup) {
groupPrivacyRules = rules;
} else {
privacyRules = rules;
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
reloadContactsStatuses();
}
......
......@@ -94,45 +94,8 @@ public class FileLoadOperation {
ext = extension != null ? extension : "jpg";
}
public FileLoadOperation(TLRPC.Video videoLocation) {
if (videoLocation instanceof TLRPC.TL_videoEncrypted) {
location = new TLRPC.TL_inputEncryptedFileLocation();
location.id = videoLocation.id;
location.access_hash = videoLocation.access_hash;
datacenter_id = videoLocation.dc_id;
iv = new byte[32];
System.arraycopy(videoLocation.iv, 0, iv, 0, iv.length);
key = videoLocation.key;
} else if (videoLocation instanceof TLRPC.TL_video) {
location = new TLRPC.TL_inputVideoFileLocation();
datacenter_id = videoLocation.dc_id;
location.id = videoLocation.id;
location.access_hash = videoLocation.access_hash;
}
totalBytesCount = videoLocation.size;
ext = ".mp4";
}
public FileLoadOperation(TLRPC.Audio audioLocation) {
if (audioLocation instanceof TLRPC.TL_audioEncrypted) {
location = new TLRPC.TL_inputEncryptedFileLocation();
location.id = audioLocation.id;
location.access_hash = audioLocation.access_hash;
datacenter_id = audioLocation.dc_id;
iv = new byte[32];
System.arraycopy(audioLocation.iv, 0, iv, 0, iv.length);
key = audioLocation.key;
} else if (audioLocation instanceof TLRPC.TL_audio) {
location = new TLRPC.TL_inputAudioFileLocation();
datacenter_id = audioLocation.dc_id;
location.id = audioLocation.id;
location.access_hash = audioLocation.access_hash;
}
totalBytesCount = audioLocation.size;
ext = ".ogg";
}
public FileLoadOperation(TLRPC.Document documentLocation) {
try {
if (documentLocation instanceof TLRPC.TL_documentEncrypted) {
location = new TLRPC.TL_inputEncryptedFileLocation();
location.id = documentLocation.id;
......@@ -150,18 +113,41 @@ public class FileLoadOperation {
if (totalBytesCount <= 0) {
totalBytesCount = documentLocation.size;
}
if (ext == null) {
ext = FileLoader.getDocumentFileName(documentLocation);
int idx;
if (ext == null || (idx = ext.lastIndexOf(".")) == -1) {
ext = "";
} else {
ext = ext.substring(idx);
}
if (ext.length() <= 1) {
if (documentLocation.mime_type != null) {
switch (documentLocation.mime_type) {
case "video/mp4":
ext = ".mp4";
break;
case "audio/ogg":
ext = ".ogg";
break;
default:
ext = "";
break;
}
} else {
ext = "";
}
}
} catch (Exception e) {
FileLog.e("tmessages", e);
state = stateFailed;
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
}
}
public void setForceRequest(boolean forceRequest) {
......@@ -187,6 +173,7 @@ public class FileLoadOperation {
delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1);
state = stateDownloading;
if (location == null) {
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
......@@ -315,7 +302,8 @@ public class FileLoadOperation {
state = stateFailed;
cleanup();
if (requestInfos != null) {
for (RequestInfo requestInfo : requestInfos) {
for (int a = 0; a < requestInfos.size(); a++) {
RequestInfo requestInfo = requestInfos.get(a);
if (requestInfo.requestToken != 0) {
ConnectionsManager.getInstance().cancelRequest(requestInfo.requestToken, true);
}
......
......@@ -1001,8 +1001,8 @@ public class ImageLoader {
}
}
if (imageReceiverArray.size() == 0) {
for (ImageReceiver receiver : imageReceiverArray) {
imageLoadingByTag.remove(receiver.getTag(thumb));
for (int a = 0; a < imageReceiverArray.size(); a++) {
imageLoadingByTag.remove(imageReceiverArray.get(a).getTag(thumb));
}
imageReceiverArray.clear();
if (location != null) {
......@@ -1233,18 +1233,7 @@ public class ImageLoader {
FileLog.e("tmessages", "file system changed");
Runnable r = new Runnable() {
public void run() {
cacheOutQueue.postRunnable(new Runnable() {
@Override
public void run() {
final HashMap<Integer, File> paths = createMediaPaths();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
FileLoader.getInstance().setMediaDirs(paths);
}
});
}
});
checkMediaPaths();
}
};
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) {
......@@ -1285,6 +1274,10 @@ public class ImageLoader {
mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath);
FileLoader.getInstance().setMediaDirs(mediaDirs);
checkMediaPaths();
}
public void checkMediaPaths() {
cacheOutQueue.postRunnable(new Runnable() {
@Override
public void run() {
......@@ -1702,7 +1695,7 @@ public class ImageLoader {
if (thumb != 2) {
CacheImage img = new CacheImage();
if (httpLocation != null && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) || imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) {
if (httpLocation != null && !httpLocation.startsWith("vthumb") && !httpLocation.startsWith("thumb") && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) || imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) {
img.animatedFile = true;
}
......@@ -1801,7 +1794,7 @@ public class ImageLoader {
}
if (httpLocation != null) {
key = Utilities.MD5(httpLocation);
url = key + "." + getHttpUrlExtension(httpLocation);
url = key + "." + getHttpUrlExtension(httpLocation, "jpg");
} else if (imageLocation != null) {
if (imageLocation instanceof TLRPC.FileLocation) {
TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation;
......@@ -1822,7 +1815,11 @@ public class ImageLoader {
docExt = "";
} else {
docExt = docExt.substring(idx);
}
if (docExt.length() <= 1) {
if (document.mime_type != null && document.mime_type.equals("video/mp4")) {
docExt = ".mp4";
} else {
docExt = "";
}
}
......@@ -1965,7 +1962,7 @@ public class ImageLoader {
ext = "jpg";
}
}
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + ext);
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + getHttpUrlExtension(url, extension));
file.delete();
HttpFileTask task = new HttpFileTask(url, file, ext);
......@@ -2279,14 +2276,14 @@ public class ImageLoader {
}
}
public static String getHttpUrlExtension(String url) {
public static String getHttpUrlExtension(String url, String defaultExt) {
String 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";
ext = defaultExt;
}
return ext;
}
......@@ -2300,10 +2297,6 @@ public class ImageLoader {
break;
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
if (message.media.video.thumb instanceof TLRPC.TL_photoCachedSize) {
photoSize = message.media.video.thumb;
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
if (message.media.document.thumb instanceof TLRPC.TL_photoCachedSize) {
photoSize = message.media.document.thumb;
......@@ -2350,8 +2343,6 @@ public class ImageLoader {
break;
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
message.media.video.thumb = newPhotoSize;
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
message.media.document.thumb = newPhotoSize;
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
......@@ -2369,7 +2360,8 @@ public class ImageLoader {
if (messages == null || messages.isEmpty()) {
return;
}
for (TLRPC.Message message : messages) {
for (int a = 0; a < messages.size(); a++) {
TLRPC.Message message = messages.get(a);
saveMessageThumbs(message);
}
}
......
......@@ -138,7 +138,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
if ((fileLocation == null && httpUrl == null && thumbLocation == null)
|| (fileLocation != null && !(fileLocation instanceof TLRPC.TL_fileLocation)
&& !(fileLocation instanceof TLRPC.TL_fileEncryptedLocation)
&& !(fileLocation instanceof TLRPC.TL_document))) {
&& !(fileLocation instanceof TLRPC.TL_document)
&& !(fileLocation instanceof TLRPC.TL_documentEncrypted))) {
recycleBitmap(null, false);
recycleBitmap(null, true);
currentKey = null;
......@@ -260,6 +261,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
}
public void setOrientation(int angle, boolean center) {
while (angle < 0) {
angle += 360;
}
while (angle > 360) {
angle -= 360;
}
orientation = angle;
centerRotation = center;
}
......@@ -376,7 +383,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
} else {
int bitmapW;
int bitmapH;
if (orientation == 90 || orientation == 270) {
if (orientation % 360 == 90 || orientation % 360 == 270) {
bitmapW = bitmapDrawable.getIntrinsicHeight();
bitmapH = bitmapDrawable.getIntrinsicWidth();
} else {
......@@ -413,7 +420,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
canvas.save();
canvas.clipRect(imageX, imageY, imageX + imageW, imageY + imageH);
if (orientation != 0) {
if (orientation % 360 != 0) {
if (centerRotation) {
canvas.rotate(orientation, imageW / 2, imageH / 2);
} else {
......@@ -428,7 +435,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
bitmapH /= scaleW;
drawRegion.set(imageX, imageY - (bitmapH - imageH) / 2, imageX + imageW, imageY + (bitmapH + imageH) / 2);
}
if (orientation == 90 || orientation == 270) {
if (orientation % 360 == 90 || orientation % 360 == 270) {
int width = (drawRegion.right - drawRegion.left) / 2;
int height = (drawRegion.bottom - drawRegion.top) / 2;
int centerX = (drawRegion.right + drawRegion.left) / 2;
......@@ -457,7 +464,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
canvas.restore();
} else {
canvas.save();
if (orientation != 0) {
if (orientation % 360 != 0) {
if (centerRotation) {
canvas.rotate(orientation, imageW / 2, imageH / 2);
} else {
......@@ -465,7 +472,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
}
}
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
if (orientation == 90 || orientation == 270) {
if (orientation % 360 == 90 || orientation % 360 == 270) {
int width = (drawRegion.right - drawRegion.left) / 2;
int height = (drawRegion.bottom - drawRegion.top) / 2;
int centerX = (drawRegion.right + drawRegion.left) / 2;
......@@ -597,18 +604,18 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
public int getBitmapWidth() {
if (currentImage instanceof AnimatedFileDrawable) {
return orientation == 0 || orientation == 180 ? currentImage.getIntrinsicWidth() : currentImage.getIntrinsicHeight();
return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicWidth() : currentImage.getIntrinsicHeight();
}
Bitmap bitmap = getBitmap();
return orientation == 0 || orientation == 180 ? bitmap.getWidth() : bitmap.getHeight();
return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getWidth() : bitmap.getHeight();
}
public int getBitmapHeight() {
if (currentImage instanceof AnimatedFileDrawable) {
return orientation == 0 || orientation == 180 ? currentImage.getIntrinsicHeight() : currentImage.getIntrinsicWidth();
return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicHeight() : currentImage.getIntrinsicWidth();
}
Bitmap bitmap = getBitmap();
return orientation == 0 || orientation == 180 ? bitmap.getHeight() : bitmap.getWidth();
return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getHeight() : bitmap.getWidth();
}
public void setVisible(boolean value, boolean invalidate) {
......
......@@ -700,6 +700,30 @@ public class LocaleController {
return "LOC_ERR";
}
public static String formatDateAudio(long date) {
try {
Calendar rightNow = Calendar.getInstance();
int day = rightNow.get(Calendar.DAY_OF_YEAR);
int year = rightNow.get(Calendar.YEAR);
rightNow.setTimeInMillis(date * 1000);
int dateDay = rightNow.get(Calendar.DAY_OF_YEAR);
int dateYear = rightNow.get(Calendar.YEAR);
if (dateDay == day && year == dateYear) {
return String.format("%s %s", LocaleController.getString("TodayAt", R.string.TodayAt), getInstance().formatterDay.format(new Date(date * 1000)));
} else if (dateDay + 1 == day && year == dateYear) {
return String.format("%s %s", LocaleController.getString("YesterdayAt", R.string.YesterdayAt), getInstance().formatterDay.format(new Date(date * 1000)));
} else if (year == dateYear) {
return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterMonth.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000)));
} else {
return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000)));
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return "LOC_ERR";
}
public static String formatDateOnline(long date) {
try {
Calendar rightNow = Calendar.getInstance();
......
......@@ -21,15 +21,13 @@ import android.media.RemoteControlClient;
import android.os.Build;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.RemoteViews;
import org.telegram.messenger.audioinfo.AudioInfo;
import org.telegram.ui.LaunchActivity;
public class MusicPlayerService extends Service implements AudioManager.OnAudioFocusChangeListener, NotificationCenter.NotificationCenterDelegate {
public class MusicPlayerService extends Service implements NotificationCenter.NotificationCenterDelegate {
public static final String NOTIFY_PREVIOUS = "org.telegram.android.musicplayer.previous";
public static final String NOTIFY_CLOSE = "org.telegram.android.musicplayer.close";
......@@ -39,8 +37,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF
private RemoteControlClient remoteControlClient;
private AudioManager audioManager;
private static boolean ignoreAudioFocus = false;
private PhoneStateListener phoneStateListener;
private static boolean supportBigNotifications = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
private static boolean supportLockScreenControls = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
......@@ -55,29 +51,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged);
try {
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
}
} else if (state == TelephonyManager.CALL_STATE_IDLE) {
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (mgr != null) {
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
super.onCreate();
}
......@@ -220,7 +193,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF
metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover());
}
metadataEditor.apply();
audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
}
......@@ -246,35 +218,11 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF
metadataEditor.clear();
metadataEditor.apply();
audioManager.unregisterRemoteControlClient(remoteControlClient);
audioManager.abandonAudioFocus(this);
}
try {
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (mgr != null) {
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged);
}
@Override
public void onAudioFocusChange(int focusChange) {
if (ignoreAudioFocus) {
ignoreAudioFocus = false;
return;
}
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
}
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
//MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
}
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.audioPlayStateChanged) {
......@@ -286,8 +234,4 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF
}
}
}
public static void setIgnoreAudioFocus() {
ignoreAudioFocus = true;
}
}
......@@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
public class NativeLoader {
private final static int LIB_VERSION = 17;
private final static int LIB_VERSION = 19;
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";
......
......@@ -77,6 +77,7 @@ public class NotificationCenter {
public static final int closeOtherAppActivities = totalEvents++;
public static final int didUpdatedConnectionState = totalEvents++;
public static final int didReceiveSmsCode = totalEvents++;
public static final int didReceiveCall = totalEvents++;
public static final int emojiDidLoaded = totalEvents++;
public static final int appDidLogout = totalEvents++;
......
......@@ -39,7 +39,7 @@ public class UserConfig {
public static int lastPauseTime = 0;
public static boolean isWaitingForPasscodeEnter = false;
public static boolean useFingerprint = true;
public static int lastUpdateVersion;
public static String lastUpdateVersion;
public static int lastContactsSyncTime;
public static int migrateOffsetId = -1;
......@@ -83,7 +83,7 @@ public class UserConfig {
editor.putInt("passcodeType", passcodeType);
editor.putInt("autoLockIn", autoLockIn);
editor.putInt("lastPauseTime", lastPauseTime);
editor.putInt("lastUpdateVersion", lastUpdateVersion);
editor.putString("lastUpdateVersion2", lastUpdateVersion);
editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
editor.putBoolean("useFingerprint", useFingerprint);
......@@ -224,7 +224,7 @@ public class UserConfig {
autoLockIn = preferences.getInt("autoLockIn", 60 * 60);
lastPauseTime = preferences.getInt("lastPauseTime", 0);
useFingerprint = preferences.getBoolean("useFingerprint", true);
lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511);
lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5");
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
migrateOffsetId = preferences.getInt("migrateOffsetId", 0);
......@@ -314,7 +314,7 @@ public class UserConfig {
lastPauseTime = 0;
useFingerprint = true;
isWaitingForPasscodeEnter = false;
lastUpdateVersion = BuildVars.BUILD_VERSION;
lastUpdateVersion = BuildVars.BUILD_VERSION_STRING;
lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60;
saveConfig(true);
}
......
......@@ -53,6 +53,7 @@ public class Utilities {
public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin);
public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length);
public native static String readlink(String path);
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length);
......
......@@ -156,7 +156,7 @@ public class ID3v2Info extends AudioInfo {
smallCover = cover;
}
}
} catch (Exception e) {
} catch (Throwable e) {
e.printStackTrace();
}
coverPictureType = picture.type;
......
......@@ -60,6 +60,9 @@ public class MessagesSearchQuery {
lastReturnedNum--;
return;
}
if (searchResultMessages.isEmpty()) {
return;
}
query = lastSearchQuery;
MessageObject messageObject = searchResultMessages.get(searchResultMessages.size() - 1);
if (messageObject.getDialogId() == dialog_id && !messagesSearchEndReached[0]) {
......
......@@ -56,11 +56,11 @@ public class SharedMediaQuery {
} else if (type == MEDIA_FILE) {
req.filter = new TLRPC.TL_inputMessagesFilterDocument();
} else if (type == MEDIA_AUDIO) {
req.filter = new TLRPC.TL_inputMessagesFilterAudio();
req.filter = new TLRPC.TL_inputMessagesFilterVoice();
} else if (type == MEDIA_URL) {
req.filter = new TLRPC.TL_inputMessagesFilterUrl();
} else if (type == MEDIA_MUSIC) {
req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments();
req.filter = new TLRPC.TL_inputMessagesFilterMusic();
}
req.q = "";
req.peer = MessagesController.getInputPeer(lower_part);
......@@ -101,11 +101,11 @@ public class SharedMediaQuery {
} else if (type == MEDIA_FILE) {
req.filter = new TLRPC.TL_inputMessagesFilterDocument();
} else if (type == MEDIA_AUDIO) {
req.filter = new TLRPC.TL_inputMessagesFilterAudio();
req.filter = new TLRPC.TL_inputMessagesFilterVoice();
} else if (type == MEDIA_URL) {
req.filter = new TLRPC.TL_inputMessagesFilterUrl();
} else if (type == MEDIA_MUSIC) {
req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments();
req.filter = new TLRPC.TL_inputMessagesFilterMusic();
}
req.q = "";
req.peer = MessagesController.getInputPeer(lower_part);
......@@ -144,8 +144,10 @@ public class SharedMediaQuery {
if (message == null) {
return -1;
}
if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) {
return MEDIA_PHOTOVIDEO;
} else if (MessageObject.isVoiceMessage(message)) {
return MEDIA_AUDIO;
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
if (MessageObject.isStickerMessage(message)) {
return -1;
......@@ -154,8 +156,6 @@ public class SharedMediaQuery {
} else {
return MEDIA_FILE;
}
} else if (message.media instanceof TLRPC.TL_messageMediaAudio) {
return MEDIA_AUDIO;
} else if (!message.entities.isEmpty()) {
for (int a = 0; a < message.entities.size(); a++) {
TLRPC.MessageEntity entity = message.entities.get(a);
......@@ -171,9 +171,7 @@ public class SharedMediaQuery {
if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) {
return false;
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto ||
message.media instanceof TLRPC.TL_messageMediaVideo ||
message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isGifDocument(message.media.document) ||
message.media instanceof TLRPC.TL_messageMediaAudio) {
message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isGifDocument(message.media.document)) {
return true;
} else if (!message.entities.isEmpty()) {
for (int a = 0; a < message.entities.size(); a++) {
......
......@@ -120,6 +120,7 @@ public class ConnectionsManager {
@Override
public void run() {
FileLog.d("tmessages", "send request " + object + " with token = " + requestToken);
try {
NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize());
object.serializeToStream(buffer);
object.freeResources();
......@@ -156,6 +157,9 @@ public class ConnectionsManager {
}
}
}, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
return requestToken;
......
......@@ -384,6 +384,7 @@ public class BottomSheet extends Dialog {
titleView.setText(title);
titleView.setTextColor(0xff757575);
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
titleView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(8));
titleView.setGravity(Gravity.CENTER_VERTICAL);
containerView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48));
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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