Merge branch 'dev'
This commit is contained in:
commit
419969f721
@ -82,7 +82,7 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 19
|
||||
versionCode 212
|
||||
versionCode 219
|
||||
versionName "1.4.9"
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,18 @@ LOCAL_SRC_FILES += \
|
||||
./opus/opusfile/opusfile.c \
|
||||
./opus/opusfile/stream.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./giflib/dgif_lib.c \
|
||||
./giflib/gifalloc.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./aes/aes_core.c \
|
||||
./aes/aes_ige.c \
|
||||
./aes/aes_misc.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./sqlite/sqlite3.c
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
./opus/include \
|
||||
./opus/silk \
|
||||
@ -163,16 +175,12 @@ LOCAL_C_INCLUDES := \
|
||||
./opus/opusfile
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./aes_core.c \
|
||||
./aes_ige.c \
|
||||
./aes_misc.c \
|
||||
./jni.c \
|
||||
./sqlite3.c \
|
||||
./org_telegram_SQLite_SQLiteCursor.c \
|
||||
./org_telegram_SQLite_SQLiteDatabase.c \
|
||||
./org_telegram_SQLite_SQLitePreparedStatement.c \
|
||||
./org_telegram_SQLite.c \
|
||||
./audio.c
|
||||
|
||||
./sqlite_cursor.c \
|
||||
./sqlite_database.c \
|
||||
./sqlite_statement.c \
|
||||
./sqlite.c \
|
||||
./audio.c \
|
||||
./gif.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
@ -5,14 +5,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <opusfile.h>
|
||||
#include "log.h"
|
||||
|
||||
#ifndef max
|
||||
#define max(x, y) ((x) > (y)) ? (x) : (y)
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#endif
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
@ -540,9 +533,6 @@ int64_t _currentPcmOffset = 0;
|
||||
int _finished = 0;
|
||||
static const int playerBuffersCount = 3;
|
||||
static const int playerSampleRate = 48000;
|
||||
int finished;
|
||||
int pcmOffset;
|
||||
int size;
|
||||
|
||||
void cleanupPlayer() {
|
||||
if (_opusFile) {
|
||||
@ -585,14 +575,14 @@ int initPlayer(const char *path) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void fillBuffer(uint8_t *buffer, int capacity) {
|
||||
void fillBuffer(uint8_t *buffer, int capacity, int *args) {
|
||||
if (_opusFile) {
|
||||
pcmOffset = max(0, op_pcm_tell(_opusFile));
|
||||
args[1] = max(0, op_pcm_tell(_opusFile));
|
||||
|
||||
if (_finished) {
|
||||
finished = 1;
|
||||
size = 0;
|
||||
pcmOffset = 0;
|
||||
args[0] = 0;
|
||||
args[1] = 0;
|
||||
args[2] = 1;
|
||||
return;
|
||||
} else {
|
||||
int writtenOutputBytes = 0;
|
||||
@ -612,19 +602,19 @@ void fillBuffer(uint8_t *buffer, int capacity) {
|
||||
}
|
||||
}
|
||||
|
||||
size = writtenOutputBytes;
|
||||
args[0] = writtenOutputBytes;
|
||||
|
||||
if (endOfFileReached || pcmOffset + size == _totalPcmDuration) {
|
||||
if (endOfFileReached || args[1] + args[0] == _totalPcmDuration) {
|
||||
_finished = 1;
|
||||
finished = 1;
|
||||
args[2] = 1;
|
||||
} else {
|
||||
finished = 0;
|
||||
args[2] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memset(buffer, 0, capacity);
|
||||
size = capacity;
|
||||
pcmOffset = _totalPcmDuration;
|
||||
args[0] = capacity;
|
||||
args[1] = _totalPcmDuration;
|
||||
}
|
||||
}
|
||||
|
||||
@ -632,21 +622,11 @@ JNIEXPORT jlong Java_org_telegram_messenger_MediaController_getTotalPcmDuration(
|
||||
return _totalPcmDuration;
|
||||
}
|
||||
|
||||
JNIEXPORT int Java_org_telegram_messenger_MediaController_getFinished(JNIEnv *env, jclass class) {
|
||||
return finished;
|
||||
}
|
||||
|
||||
JNIEXPORT int Java_org_telegram_messenger_MediaController_getSize(JNIEnv *env, jclass class) {
|
||||
return size;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong Java_org_telegram_messenger_MediaController_getPcmOffset(JNIEnv *env, jclass class) {
|
||||
return pcmOffset;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_MediaController_readOpusFile(JNIEnv *env, jclass class, jobject buffer, jint capacity) {
|
||||
JNIEXPORT void Java_org_telegram_messenger_MediaController_readOpusFile(JNIEnv *env, jclass class, jobject buffer, jint capacity, jintArray args) {
|
||||
jint *argsArr = (*env)->GetIntArrayElements(env, args, 0);
|
||||
jbyte *bufferBytes = (*env)->GetDirectBufferAddress(env, buffer);
|
||||
fillBuffer(bufferBytes, capacity);
|
||||
fillBuffer(bufferBytes, capacity, argsArr);
|
||||
(*env)->ReleaseIntArrayElements(env, args, argsArr, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT int Java_org_telegram_messenger_MediaController_seekOpusFile(JNIEnv *env, jclass class, jfloat position) {
|
||||
|
@ -1,128 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function build_one {
|
||||
|
||||
echo "Cleaning..."
|
||||
make clean
|
||||
|
||||
echo "Configuring..."
|
||||
|
||||
./configure --target-os=linux \
|
||||
--prefix=$PREFIX \
|
||||
--enable-cross-compile \
|
||||
--extra-libs="-lgcc" \
|
||||
--arch=$ARCH \
|
||||
--cc=$CC \
|
||||
--cross-prefix=$CROSS_PREFIX \
|
||||
--nm=$NM \
|
||||
--sysroot=$PLATFORM \
|
||||
--extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -fasm -Wno-psabi -fno-short-enums -Dipv6mr_interface=ipv6mr_ifindex -fno-strict-aliasing -finline-limit=300 $OPTIMIZE_CFLAGS " \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl" \
|
||||
\
|
||||
--disable-everything \
|
||||
--disable-network \
|
||||
--enable-small \
|
||||
--enable-zlib \
|
||||
--disable-avfilter \
|
||||
--disable-avdevice \
|
||||
--disable-programs \
|
||||
--disable-doc \
|
||||
--disable-lsp \
|
||||
--disable-dwt \
|
||||
--disable-dct \
|
||||
--enable-stripping \
|
||||
--disable-postproc \
|
||||
--disable-fft \
|
||||
--disable-lzo \
|
||||
--disable-rdft \
|
||||
--disable-mdct \
|
||||
--disable-debug \
|
||||
\
|
||||
--enable-muxer='mp4' \
|
||||
--enable-protocol='file' \
|
||||
--enable-encoder='aac,mpeg4' \
|
||||
--enable-decoder='aac,amrnb,amrwb,flv,h263,h264' \
|
||||
--enable-demuxer='flv,mpegvideo,mov' \
|
||||
--enable-hwaccel='mpeg4_vaapi,mpeg4_vdpau' \
|
||||
--enable-swresample \
|
||||
--enable-swscale \
|
||||
--enable-asm \
|
||||
$ADDITIONAL_CONFIGURE_FLAG
|
||||
|
||||
echo "continue?"
|
||||
read
|
||||
make -j8 install
|
||||
|
||||
#$AR d libavcodec/libavcodec.a inverse.o
|
||||
|
||||
#$LD -rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -soname libffmpeg.a -static -nostdlib -z noexecstack -Bsymbolic --whole-archive --no-undefined -o $PREFIX/libffmpeg.so libavcodec/libavcodec.a libavformat/libavformat.a libavutil/libavutil.a -lc -lm -lz -ldl --dynamic-linker=/system/bin/linker $GCCLIB
|
||||
|
||||
}
|
||||
|
||||
NDK=/Users/DrKLO/ndk9
|
||||
|
||||
#arm platform
|
||||
PLATFORM=$NDK/platforms/android-8/arch-arm
|
||||
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64
|
||||
LD=$PREBUILT/bin/arm-linux-androideabi-ld
|
||||
AR=$PREBUILT/bin/arm-linux-androideabi-ar
|
||||
NM=$PREBUILT/bin/arm-linux-androideabi-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/arm-linux-androideabi/4.8/libgcc.a
|
||||
ARCH=arm
|
||||
CC=$PREBUILT/bin/arm-linux-androideabi-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/arm-linux-androideabi-
|
||||
|
||||
#arm v6
|
||||
CPU=armv6
|
||||
OPTIMIZE_CFLAGS="-marm -march=$CPU"
|
||||
PREFIX=/Users/DrKLO/ndk9/platforms/android-9/arch-$ARCH/usr
|
||||
ADDITIONAL_CONFIGURE_FLAG=
|
||||
build_one
|
||||
|
||||
#arm v7vfpv3
|
||||
#CPU=armv7-a
|
||||
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=$CPU "
|
||||
#PREFIX=./android/$CPU
|
||||
#ADDITIONAL_CONFIGURE_FLAG=
|
||||
#build_one
|
||||
|
||||
#arm v7vfp
|
||||
#CPU=armv7-a
|
||||
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
|
||||
#PREFIX=./android/$CPU-vfp
|
||||
#ADDITIONAL_CONFIGURE_FLAG=
|
||||
#build_one
|
||||
|
||||
#arm v7n
|
||||
#CPU=armv7-a
|
||||
#OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=neon -marm -march=$CPU -mtune=cortex-a8"
|
||||
#PREFIX=./android/$CPU
|
||||
#ADDITIONAL_CONFIGURE_FLAG=--enable-neon
|
||||
#build_one
|
||||
|
||||
#arm v6+vfp
|
||||
#CPU=armv6
|
||||
#OPTIMIZE_CFLAGS="-DCMP_HAVE_VFP -mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU"
|
||||
#PREFIX=./android/${CPU}_vfp
|
||||
#ADDITIONAL_CONFIGURE_FLAG=
|
||||
#build_one
|
||||
|
||||
#x86 platform
|
||||
PLATFORM=$NDK/platforms/android-9/arch-x86
|
||||
PREBUILT=$NDK/toolchains/x86-4.8/prebuilt/darwin-x86_64
|
||||
LD=$PREBUILT/bin/i686-linux-android-ld
|
||||
AR=$PREBUILT/bin/i686-linux-android-ar
|
||||
NM=$PREBUILT/bin/i686-linux-android-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/i686-linux-android/4.8/libgcc.a
|
||||
ARCH=x86
|
||||
CC=$PREBUILT/bin/i686-linux-android-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/i686-linux-android-
|
||||
|
||||
CPU=i686
|
||||
OPTIMIZE_CFLAGS="-march=$CPU"
|
||||
PREFIX=/Users/DrKLO/ndk9/platforms/android-9/arch-$ARCH/usr
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-mmx --disable-yasm"
|
||||
build_one
|
||||
|
827
TMessagesProj/jni/gif.c
Normal file
827
TMessagesProj/jni/gif.c
Normal file
@ -0,0 +1,827 @@
|
||||
//tanks to https://github.com/koral--/android-gif-drawable
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
// Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include "gif.h"
|
||||
#include "giflib/gif_lib.h"
|
||||
|
||||
#define D_GIF_ERR_NO_FRAMES 1000
|
||||
#define D_GIF_ERR_INVALID_SCR_DIMS 1001
|
||||
#define D_GIF_ERR_INVALID_IMG_DIMS 1002
|
||||
#define D_GIF_ERR_IMG_NOT_CONFINED 1003
|
||||
|
||||
typedef struct {
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
} argb;
|
||||
|
||||
typedef struct {
|
||||
unsigned int duration;
|
||||
short transpIndex;
|
||||
unsigned char disposalMethod;
|
||||
} FrameInfo;
|
||||
|
||||
typedef struct {
|
||||
GifFileType *gifFilePtr;
|
||||
unsigned long lastFrameReaminder;
|
||||
unsigned long nextStartTime;
|
||||
int currentIndex;
|
||||
unsigned int lastDrawIndex;
|
||||
FrameInfo *infos;
|
||||
argb *backupPtr;
|
||||
int startPos;
|
||||
unsigned char *rasterBits;
|
||||
char *comment;
|
||||
unsigned short loopCount;
|
||||
int currentLoop;
|
||||
jfloat speedFactor;
|
||||
} GifInfo;
|
||||
|
||||
static ColorMapObject *defaultCmap = NULL;
|
||||
|
||||
static ColorMapObject *genDefColorMap(void) {
|
||||
ColorMapObject *cmap = GifMakeMapObject(256, NULL);
|
||||
if (cmap != NULL) {
|
||||
int iColor;
|
||||
for (iColor = 0; iColor < 256; iColor++) {
|
||||
cmap->Colors[iColor].Red = (GifByteType) iColor;
|
||||
cmap->Colors[iColor].Green = (GifByteType) iColor;
|
||||
cmap->Colors[iColor].Blue = (GifByteType) iColor;
|
||||
}
|
||||
}
|
||||
return cmap;
|
||||
}
|
||||
|
||||
jint gifOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
|
||||
defaultCmap = genDefColorMap();
|
||||
if (defaultCmap == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
void gifOnJNIUnload(JavaVM *vm, void *reserved) {
|
||||
GifFreeMapObject(defaultCmap);
|
||||
}
|
||||
|
||||
static int fileReadFunc(GifFileType *gif, GifByteType *bytes, int size) {
|
||||
FILE *file = (FILE *)gif->UserData;
|
||||
return fread(bytes, 1, size, file);
|
||||
}
|
||||
|
||||
static int fileRewindFun(GifInfo *info) {
|
||||
return fseek(info->gifFilePtr->UserData, info->startPos, SEEK_SET);
|
||||
}
|
||||
|
||||
static unsigned long getRealTime() {
|
||||
struct timespec ts;
|
||||
const clockid_t id = CLOCK_MONOTONIC;
|
||||
if (id != (clockid_t) - 1 && clock_gettime(id, &ts) != -1)
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void cleanUp(GifInfo *info) {
|
||||
if (info->backupPtr) {
|
||||
free(info->backupPtr);
|
||||
info->backupPtr = NULL;
|
||||
}
|
||||
if (info->infos) {
|
||||
free(info->infos);
|
||||
info->infos = NULL;
|
||||
}
|
||||
if (info->rasterBits) {
|
||||
free(info->rasterBits);
|
||||
info->rasterBits = NULL;
|
||||
}
|
||||
if (info->comment) {
|
||||
free(info->comment);
|
||||
info->comment = NULL;
|
||||
}
|
||||
|
||||
GifFileType *GifFile = info->gifFilePtr;
|
||||
if (GifFile->SColorMap == defaultCmap) {
|
||||
GifFile->SColorMap = NULL;
|
||||
}
|
||||
if (GifFile->SavedImages != NULL) {
|
||||
SavedImage *sp;
|
||||
for (sp = GifFile->SavedImages; sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||
sp->ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
}
|
||||
free(GifFile->SavedImages);
|
||||
GifFile->SavedImages = NULL;
|
||||
}
|
||||
DGifCloseFile(GifFile);
|
||||
free(info);
|
||||
}
|
||||
|
||||
static int getComment(GifByteType *Bytes, char **cmt) {
|
||||
unsigned int len = (unsigned int) Bytes[0];
|
||||
unsigned int offset = *cmt != NULL ? strlen(*cmt) : 0;
|
||||
char *ret = realloc(*cmt, (len + offset + 1) * sizeof(char));
|
||||
if (ret != NULL) {
|
||||
memcpy(ret + offset, &Bytes[1], len);
|
||||
ret[len + offset] = 0;
|
||||
*cmt = ret;
|
||||
return GIF_OK;
|
||||
}
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
static void packARGB32(argb *pixel, GifByteType alpha, GifByteType red, GifByteType green, GifByteType blue) {
|
||||
pixel->alpha = alpha;
|
||||
pixel->red = red;
|
||||
pixel->green = green;
|
||||
pixel->blue = blue;
|
||||
}
|
||||
|
||||
static void getColorFromTable(int idx, argb *dst, const ColorMapObject *cmap) {
|
||||
char colIdx = idx >= cmap->ColorCount ? 0 : idx;
|
||||
GifColorType *col = &cmap->Colors[colIdx];
|
||||
packARGB32(dst, 0xFF, col->Red, col->Green, col->Blue);
|
||||
}
|
||||
|
||||
static void eraseColor(argb *bm, int w, int h, argb color) {
|
||||
int i;
|
||||
for (i = 0; i < w * h; i++) {
|
||||
*(bm + i) = color;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool setupBackupBmp(GifInfo *info, short transpIndex) {
|
||||
GifFileType *fGIF = info->gifFilePtr;
|
||||
info->backupPtr = calloc(fGIF->SWidth * fGIF->SHeight, sizeof(argb));
|
||||
if (!info->backupPtr) {
|
||||
info->gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return false;
|
||||
}
|
||||
argb paintingColor;
|
||||
if (transpIndex == -1) {
|
||||
getColorFromTable(fGIF->SBackGroundColor, &paintingColor, fGIF->SColorMap);
|
||||
} else {
|
||||
packARGB32(&paintingColor,0,0,0,0);
|
||||
}
|
||||
eraseColor(info->backupPtr, fGIF->SWidth, fGIF->SHeight, paintingColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int readExtensions(int ExtFunction, GifByteType *ExtData, GifInfo *info) {
|
||||
if (ExtData == NULL) {
|
||||
return GIF_OK;
|
||||
}
|
||||
if (ExtFunction == GRAPHICS_EXT_FUNC_CODE && ExtData[0] == 4) {
|
||||
FrameInfo *fi = &info->infos[info->gifFilePtr->ImageCount];
|
||||
fi->transpIndex = -1;
|
||||
char *b = (char *)ExtData + 1;
|
||||
short delay = ((b[2] << 8) | b[1]);
|
||||
fi->duration = delay > 1 ? delay * 10 : 100;
|
||||
fi->disposalMethod = ((b[0] >> 2) & 7);
|
||||
if (ExtData[1] & 1)
|
||||
fi->transpIndex = (short) b[3];
|
||||
if (fi->disposalMethod == 3 && info->backupPtr == NULL) {
|
||||
if (!setupBackupBmp(info,fi->transpIndex)) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
} else if (ExtFunction == COMMENT_EXT_FUNC_CODE) {
|
||||
if (getComment(ExtData, &info->comment) == GIF_ERROR) {
|
||||
info->gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
} else if (ExtFunction == APPLICATION_EXT_FUNC_CODE && ExtData[0] == 11) {
|
||||
if (strncmp("NETSCAPE2.0", &ExtData[1], 11) == 0 || strncmp("ANIMEXTS1.0", &ExtData[1], 11) == 0) {
|
||||
if (DGifGetExtensionNext(info->gifFilePtr, &ExtData, &ExtFunction) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (ExtFunction == APPLICATION_EXT_FUNC_CODE && ExtData[0] == 3 && ExtData[1] == 1) {
|
||||
info->loopCount = (unsigned short) (ExtData[2] + (ExtData[3] << 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
static int DDGifSlurp(GifFileType *GifFile, GifInfo *info, bool shouldDecode) {
|
||||
GifRecordType RecordType;
|
||||
GifByteType *ExtData;
|
||||
int codeSize;
|
||||
int ExtFunction;
|
||||
size_t ImageSize;
|
||||
do {
|
||||
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE: {
|
||||
if (DGifGetImageDesc(GifFile, !shouldDecode) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
int i = shouldDecode ? info->currentIndex : GifFile->ImageCount - 1;
|
||||
SavedImage *sp = &GifFile->SavedImages[i];
|
||||
ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
|
||||
|
||||
if (sp->ImageDesc.Width < 1 || sp->ImageDesc.Height < 1 || ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
|
||||
GifFile->Error = D_GIF_ERR_INVALID_IMG_DIMS;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (sp->ImageDesc.Width > GifFile->SWidth || sp->ImageDesc.Height > GifFile->SHeight) {
|
||||
GifFile->Error = D_GIF_ERR_IMG_NOT_CONFINED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (shouldDecode) {
|
||||
sp->RasterBits = info->rasterBits;
|
||||
if (sp->ImageDesc.Interlace) {
|
||||
int i, j;
|
||||
int InterlacedOffset[] = { 0, 4, 2, 1 };
|
||||
int InterlacedJumps[] = { 8, 8, 4, 2 };
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = InterlacedOffset[i]; j < sp->ImageDesc.Height; j += InterlacedJumps[i]) {
|
||||
if (DGifGetLine(GifFile, sp->RasterBits + j * sp->ImageDesc.Width, sp->ImageDesc.Width) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DGifGetLine(GifFile, sp->RasterBits, ImageSize) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
if (info->currentIndex >= GifFile->ImageCount - 1) {
|
||||
if (info->loopCount > 0)
|
||||
info->currentLoop++;
|
||||
if (fileRewindFun(info) != 0) {
|
||||
info->gifFilePtr->Error = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
return GIF_OK;
|
||||
} else {
|
||||
if (DGifGetCode(GifFile, &codeSize, &ExtData) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
while (ExtData) {
|
||||
if (DGifGetCodeNext(GifFile, &ExtData) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EXTENSION_RECORD_TYPE: {
|
||||
if (DGifGetExtension(GifFile, &ExtFunction, &ExtData) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (!shouldDecode) {
|
||||
info->infos = realloc(info->infos, (GifFile->ImageCount + 1) * sizeof(FrameInfo));
|
||||
if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
while (ExtData) {
|
||||
if (DGifGetExtensionNext(GifFile, &ExtData, &ExtFunction) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (!shouldDecode) {
|
||||
if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
bool ok = true;
|
||||
if (shouldDecode) {
|
||||
ok = (fileRewindFun(info) == 0);
|
||||
}
|
||||
if (ok) {
|
||||
return GIF_OK;
|
||||
} else {
|
||||
info->gifFilePtr->Error = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyLine(argb *dst, const unsigned char *src, const ColorMapObject *cmap, int transparent, int width) {
|
||||
for (; width > 0; width--, src++, dst++) {
|
||||
if (*src != transparent) {
|
||||
getColorFromTable(*src, dst, cmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static argb *getAddr(argb *bm, int width, int left, int top) {
|
||||
return bm + top * width + left;
|
||||
}
|
||||
|
||||
static void blitNormal(argb *bm, int width, int height, const SavedImage *frame, const ColorMapObject *cmap, int transparent) {
|
||||
const unsigned char *src = (unsigned char *)frame->RasterBits;
|
||||
argb *dst = getAddr(bm, width, frame->ImageDesc.Left, frame->ImageDesc.Top);
|
||||
GifWord copyWidth = frame->ImageDesc.Width;
|
||||
if (frame->ImageDesc.Left + copyWidth > width) {
|
||||
copyWidth = width - frame->ImageDesc.Left;
|
||||
}
|
||||
|
||||
GifWord copyHeight = frame->ImageDesc.Height;
|
||||
if (frame->ImageDesc.Top + copyHeight > height) {
|
||||
copyHeight = height - frame->ImageDesc.Top;
|
||||
}
|
||||
|
||||
int srcPad, dstPad;
|
||||
dstPad = width - copyWidth;
|
||||
srcPad = frame->ImageDesc.Width - copyWidth;
|
||||
for (; copyHeight > 0; copyHeight--) {
|
||||
copyLine(dst, src, cmap, transparent, copyWidth);
|
||||
src += frame->ImageDesc.Width;
|
||||
dst += width;
|
||||
}
|
||||
}
|
||||
|
||||
static void fillRect(argb *bm, int bmWidth, int bmHeight, GifWord left, GifWord top, GifWord width, GifWord height, argb col) {
|
||||
uint32_t *dst = (uint32_t *)getAddr(bm, bmWidth, left, top);
|
||||
GifWord copyWidth = width;
|
||||
if (left + copyWidth > bmWidth) {
|
||||
copyWidth = bmWidth - left;
|
||||
}
|
||||
|
||||
GifWord copyHeight = height;
|
||||
if (top + copyHeight > bmHeight) {
|
||||
copyHeight = bmHeight - top;
|
||||
}
|
||||
uint32_t *pColor = (uint32_t *)(&col);
|
||||
for (; copyHeight > 0; copyHeight--) {
|
||||
memset(dst, *pColor, copyWidth * sizeof(argb));
|
||||
dst += bmWidth;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawFrame(argb *bm, int bmWidth, int bmHeight, const SavedImage *frame, const ColorMapObject *cmap, short transpIndex) {
|
||||
if (frame->ImageDesc.ColorMap != NULL) {
|
||||
cmap = frame->ImageDesc.ColorMap;
|
||||
if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
|
||||
cmap = defaultCmap;
|
||||
}
|
||||
}
|
||||
|
||||
blitNormal(bm, bmWidth, bmHeight, frame, cmap, (int) transpIndex);
|
||||
}
|
||||
|
||||
static bool checkIfCover(const SavedImage *target, const SavedImage *covered) {
|
||||
if (target->ImageDesc.Left <= covered->ImageDesc.Left
|
||||
&& covered->ImageDesc.Left + covered->ImageDesc.Width
|
||||
<= target->ImageDesc.Left + target->ImageDesc.Width
|
||||
&& target->ImageDesc.Top <= covered->ImageDesc.Top
|
||||
&& covered->ImageDesc.Top + covered->ImageDesc.Height
|
||||
<= target->ImageDesc.Top + target->ImageDesc.Height) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void disposeFrameIfNeeded(argb *bm, GifInfo *info, unsigned int idx) {
|
||||
argb *backup = info->backupPtr;
|
||||
argb color;
|
||||
packARGB32(&color, 0, 0, 0, 0);
|
||||
GifFileType *fGif = info->gifFilePtr;
|
||||
SavedImage *cur = &fGif->SavedImages[idx - 1];
|
||||
SavedImage *next = &fGif->SavedImages[idx];
|
||||
bool curTrans = info->infos[idx - 1].transpIndex != -1;
|
||||
int curDisposal = info->infos[idx - 1].disposalMethod;
|
||||
bool nextTrans = info->infos[idx].transpIndex != -1;
|
||||
int nextDisposal = info->infos[idx].disposalMethod;
|
||||
|
||||
argb *tmp;
|
||||
if ((curDisposal == 2 || curDisposal == 3) && (nextTrans || !checkIfCover(next, cur))) {
|
||||
switch (curDisposal) {
|
||||
case 2: {
|
||||
fillRect(bm, fGif->SWidth, fGif->SHeight, cur->ImageDesc.Left, cur->ImageDesc.Top, cur->ImageDesc.Width, cur->ImageDesc.Height, color);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: {
|
||||
tmp = bm;
|
||||
bm = backup;
|
||||
backup = tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextDisposal == 3) {
|
||||
memcpy(backup, bm, fGif->SWidth * fGif->SHeight * sizeof(argb));
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean reset(GifInfo *info) {
|
||||
if (fileRewindFun(info) != 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
info->nextStartTime = 0;
|
||||
info->currentLoop = -1;
|
||||
info->currentIndex = -1;
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static void getBitmap(argb *bm, GifInfo *info) {
|
||||
GifFileType *fGIF = info->gifFilePtr;
|
||||
|
||||
argb paintingColor;
|
||||
int i = info->currentIndex;
|
||||
if (DDGifSlurp(fGIF, info, true) == GIF_ERROR) {
|
||||
return; //TODO add leniency support
|
||||
}
|
||||
SavedImage *cur = &fGIF->SavedImages[i];
|
||||
|
||||
short transpIndex = info->infos[i].transpIndex;
|
||||
if (i == 0) {
|
||||
if (transpIndex == -1) {
|
||||
getColorFromTable(fGIF->SBackGroundColor, &paintingColor, fGIF->SColorMap);
|
||||
} else {
|
||||
packARGB32(&paintingColor, 0, 0, 0, 0);
|
||||
}
|
||||
eraseColor(bm, fGIF->SWidth, fGIF->SHeight, paintingColor);
|
||||
} else {
|
||||
disposeFrameIfNeeded(bm, info, i);
|
||||
}
|
||||
drawFrame(bm, fGIF->SWidth, fGIF->SHeight, cur, fGIF->SColorMap, transpIndex);
|
||||
}
|
||||
|
||||
static void setMetaData(int width, int height, int ImageCount, int errorCode, JNIEnv *env, jintArray metaData) {
|
||||
jint *ints = (*env)->GetIntArrayElements(env, metaData, 0);
|
||||
*ints++ = width;
|
||||
*ints++ = height;
|
||||
*ints++ = ImageCount;
|
||||
*ints = errorCode;
|
||||
(*env)->ReleaseIntArrayElements(env, metaData, ints, 0);
|
||||
}
|
||||
|
||||
static jint open(GifFileType *GifFileIn, int Error, int startPos, JNIEnv *env, jintArray metaData) {
|
||||
if (startPos < 0) {
|
||||
Error = D_GIF_ERR_NOT_READABLE;
|
||||
DGifCloseFile(GifFileIn);
|
||||
}
|
||||
if (Error != 0 || GifFileIn == NULL) {
|
||||
setMetaData(0, 0, 0, Error, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
int width = GifFileIn->SWidth, height = GifFileIn->SHeight;
|
||||
unsigned int wxh = width * height;
|
||||
if (wxh < 1 || wxh > INT_MAX) {
|
||||
DGifCloseFile(GifFileIn);
|
||||
setMetaData(width, height, 0, D_GIF_ERR_INVALID_SCR_DIMS, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
GifInfo *info = malloc(sizeof(GifInfo));
|
||||
if (info == NULL) {
|
||||
DGifCloseFile(GifFileIn);
|
||||
setMetaData(width, height, 0, D_GIF_ERR_NOT_ENOUGH_MEM, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
info->gifFilePtr = GifFileIn;
|
||||
info->startPos = startPos;
|
||||
info->currentIndex = -1;
|
||||
info->nextStartTime = 0;
|
||||
info->lastFrameReaminder = ULONG_MAX;
|
||||
info->comment = NULL;
|
||||
info->loopCount = 0;
|
||||
info->currentLoop = -1;
|
||||
info->speedFactor = 1.0;
|
||||
info->rasterBits = calloc(GifFileIn->SHeight * GifFileIn->SWidth, sizeof(GifPixelType));
|
||||
info->infos = malloc(sizeof(FrameInfo));
|
||||
info->infos->duration = 0;
|
||||
info->infos->disposalMethod = 0;
|
||||
info->infos->transpIndex = -1;
|
||||
info->backupPtr = NULL;
|
||||
|
||||
if (info->rasterBits == NULL || info->infos == NULL) {
|
||||
cleanUp(info);
|
||||
setMetaData(width, height, 0, D_GIF_ERR_NOT_ENOUGH_MEM, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
|
||||
if (DDGifSlurp(GifFileIn, info, false) == GIF_ERROR) {
|
||||
Error = GifFileIn->Error;
|
||||
}
|
||||
if (GifFileIn->SColorMap == NULL || GifFileIn->SColorMap->ColorCount != (1 << GifFileIn->SColorMap->BitsPerPixel)) {
|
||||
GifFreeMapObject(GifFileIn->SColorMap);
|
||||
GifFileIn->SColorMap = defaultCmap;
|
||||
}
|
||||
int imgCount = GifFileIn->ImageCount;
|
||||
if (imgCount < 1) {
|
||||
Error = D_GIF_ERR_NO_FRAMES;
|
||||
}
|
||||
if (fileRewindFun(info) != 0) {
|
||||
Error = D_GIF_ERR_READ_FAILED;
|
||||
}
|
||||
if (Error != 0) {
|
||||
cleanUp(info);
|
||||
}
|
||||
setMetaData(width, height, imgCount, Error, env, metaData);
|
||||
|
||||
return (jint)(Error == 0 ? info : NULL);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_telegram_ui_Views_GifDrawable_getAllocationByteCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int pxCount = info->gifFilePtr->SWidth + info->gifFilePtr->SHeight;
|
||||
jlong sum = pxCount * sizeof(char);
|
||||
if (info->backupPtr != NULL) {
|
||||
sum += pxCount * sizeof(argb);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_telegram_ui_Views_GifDrawable_reset(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return reset(info);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_setSpeedFactor(JNIEnv *env, jclass class, jobject gifInfo, jfloat factor) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
info->speedFactor = factor;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToTime(JNIEnv *env, jclass class, jobject gifInfo, jint desiredPos, jintArray jPixels) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
int imgCount = info->gifFilePtr->ImageCount;
|
||||
if (imgCount <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long sum = 0;
|
||||
int i;
|
||||
for (i = 0; i < imgCount; i++) {
|
||||
unsigned long newSum = sum + info->infos[i].duration;
|
||||
if (newSum >= desiredPos) {
|
||||
break;
|
||||
}
|
||||
sum = newSum;
|
||||
}
|
||||
if (i < info->currentIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long lastFrameRemainder = desiredPos - sum;
|
||||
if (i == imgCount - 1 && lastFrameRemainder > info->infos[i].duration) {
|
||||
lastFrameRemainder = info->infos[i].duration;
|
||||
}
|
||||
info->lastFrameReaminder = lastFrameRemainder;
|
||||
if (i > info->currentIndex) {
|
||||
jint *pixels = (*env)->GetIntArrayElements(env, jPixels, 0);
|
||||
while (info->currentIndex <= i) {
|
||||
info->currentIndex++;
|
||||
getBitmap((argb *)pixels, info);
|
||||
}
|
||||
(*env)->ReleaseIntArrayElements(env, jPixels, pixels, 0);
|
||||
}
|
||||
if (info->speedFactor == 1.0) {
|
||||
info->nextStartTime = getRealTime() + lastFrameRemainder;
|
||||
} else {
|
||||
info->nextStartTime = getRealTime() + lastFrameRemainder * info->speedFactor;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToFrame(JNIEnv *env, jclass class, jobject gifInfo, jint desiredIdx, jintArray jPixels) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
if (desiredIdx <= info->currentIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
int imgCount = info->gifFilePtr->ImageCount;
|
||||
if (imgCount <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (desiredIdx >= imgCount) {
|
||||
desiredIdx = imgCount - 1;
|
||||
}
|
||||
|
||||
info->lastFrameReaminder = 0;
|
||||
jint *pixels = (*env)->GetIntArrayElements(env, jPixels, 0);
|
||||
while (info->currentIndex < desiredIdx) {
|
||||
info->currentIndex++;
|
||||
getBitmap((argb *)pixels, info);
|
||||
}
|
||||
(*env)->ReleaseIntArrayElements(env, jPixels, pixels, 0);
|
||||
if (info->speedFactor == 1.0) {
|
||||
info->nextStartTime = getRealTime() + info->infos[info->currentIndex].duration;
|
||||
} else {
|
||||
info->nextStartTime = getRealTime() + info->infos[info->currentIndex].duration * info->speedFactor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_renderFrame(JNIEnv *env, jclass class, jintArray jPixels, jobject gifInfo, jintArray metaData) {
|
||||
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool needRedraw = false;
|
||||
unsigned long rt = getRealTime();
|
||||
|
||||
if (rt >= info->nextStartTime && info->currentLoop < info->loopCount) {
|
||||
if (++info->currentIndex >= info->gifFilePtr->ImageCount) {
|
||||
info->currentIndex = 0;
|
||||
}
|
||||
needRedraw = true;
|
||||
}
|
||||
jint *rawMetaData = (*env)->GetIntArrayElements(env, metaData, 0);
|
||||
|
||||
if (needRedraw) {
|
||||
jint *pixels = (*env)->GetIntArrayElements(env, jPixels, 0);
|
||||
getBitmap((argb *)pixels, info);
|
||||
rawMetaData[3] = info->gifFilePtr->Error;
|
||||
|
||||
(*env)->ReleaseIntArrayElements(env, jPixels, pixels, 0);
|
||||
|
||||
int scaledDuration = info->infos[info->currentIndex].duration;
|
||||
if (info->speedFactor != 1.0) {
|
||||
scaledDuration /= info->speedFactor;
|
||||
}
|
||||
info->nextStartTime = rt + scaledDuration;
|
||||
rawMetaData[4] = scaledDuration;
|
||||
} else {
|
||||
rawMetaData[4] = (int) (rt - info->nextStartTime);
|
||||
}
|
||||
(*env)->ReleaseIntArrayElements(env, metaData, rawMetaData, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_free(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
if (gifInfo == NULL) {
|
||||
return;
|
||||
}
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
FILE *file = info->gifFilePtr->UserData;
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
info->gifFilePtr->UserData = NULL;
|
||||
cleanUp(info);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_telegram_ui_Views_GifDrawable_getComment(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
if (gifInfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
return (*env)->NewStringUTF(env, info->comment);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getLoopCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
if (gifInfo == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return ((GifInfo *)gifInfo)->loopCount;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getDuration(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
unsigned long sum = 0;
|
||||
for (i = 0; i < info->gifFilePtr->ImageCount; i++) {
|
||||
sum += info->infos[i].duration;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getCurrentPosition(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int idx = info->currentIndex;
|
||||
if (idx < 0 || info->gifFilePtr->ImageCount <= 1) {
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
unsigned int sum = 0;
|
||||
for (i = 0; i < idx; i++) {
|
||||
sum += info->infos[i].duration;
|
||||
}
|
||||
unsigned long remainder = info->lastFrameReaminder == ULONG_MAX ? getRealTime() - info->nextStartTime : info->lastFrameReaminder;
|
||||
return (int) (sum + remainder);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_saveRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
info->lastFrameReaminder = getRealTime() - info->nextStartTime;
|
||||
if (info->lastFrameReaminder > 0) {
|
||||
info->lastFrameReaminder = 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_restoreRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||
GifInfo *info = (GifInfo *)gifInfo;
|
||||
if (info == NULL || info->lastFrameReaminder == ULONG_MAX) {
|
||||
return;
|
||||
}
|
||||
info->nextStartTime = getRealTime() + info->lastFrameReaminder;
|
||||
info->lastFrameReaminder = ULONG_MAX;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_openFile(JNIEnv *env, jclass class, jintArray metaData, jstring jfname) {
|
||||
if (jfname == NULL) {
|
||||
setMetaData(0, 0, 0, D_GIF_ERR_OPEN_FAILED, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
|
||||
const char *fname = (*env)->GetStringUTFChars(env, jfname, 0);
|
||||
FILE *file = fopen(fname, "rb");
|
||||
(*env)->ReleaseStringUTFChars(env, jfname, fname);
|
||||
if (file == NULL) {
|
||||
setMetaData(0, 0, 0, D_GIF_ERR_OPEN_FAILED, env, metaData);
|
||||
return (jint) NULL;
|
||||
}
|
||||
int Error = 0;
|
||||
GifFileType *GifFileIn = DGifOpen(file, &fileReadFunc, &Error);
|
||||
return open(GifFileIn, Error, ftell(file), env, metaData);
|
||||
}
|
7
TMessagesProj/jni/gif.h
Normal file
7
TMessagesProj/jni/gif.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef gif_h
|
||||
#define gif_h
|
||||
|
||||
jint gifOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env);
|
||||
void gifOnJNIUnload(JavaVM *vm, void *reserved);
|
||||
|
||||
#endif
|
13
TMessagesProj/jni/giflib/config.h
Executable file
13
TMessagesProj/jni/giflib/config.h
Executable file
@ -0,0 +1,13 @@
|
||||
|
||||
// giflib config.h
|
||||
|
||||
#ifndef GIF_CONFIG_H_DEFINED
|
||||
#define GIF_CONFIG_H_DEFINED
|
||||
|
||||
#include <sys/types.h>
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_FCNTL_H
|
||||
|
||||
typedef uint32_t UINT32;
|
||||
|
||||
#endif
|
1167
TMessagesProj/jni/giflib/dgif_lib.c
Executable file
1167
TMessagesProj/jni/giflib/dgif_lib.c
Executable file
File diff suppressed because it is too large
Load Diff
132
TMessagesProj/jni/giflib/gif_hash.c
Executable file
132
TMessagesProj/jni/giflib/gif_hash.c
Executable file
@ -0,0 +1,132 @@
|
||||
/*****************************************************************************
|
||||
|
||||
gif_hash.c -- module to support the following operations:
|
||||
|
||||
1. InitHashTable - initialize hash table.
|
||||
2. ClearHashTable - clear the hash table to an empty state.
|
||||
2. InsertHashTable - insert one item into data structure.
|
||||
3. ExistsHashTable - test if item exists in data structure.
|
||||
|
||||
This module is used to hash the GIF codes during encoding.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
#include "gif_lib_private.h"
|
||||
|
||||
/* #define DEBUG_HIT_RATE Debug number of misses per hash Insert/Exists. */
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
static long NumberOfTests = 0,
|
||||
NumberOfMisses = 0;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
static int KeyItem(uint32_t Item);
|
||||
|
||||
/******************************************************************************
|
||||
Initialize HashTable - allocate the memory needed and clear it. *
|
||||
******************************************************************************/
|
||||
GifHashTableType *_InitHashTable(void)
|
||||
{
|
||||
GifHashTableType *HashTable;
|
||||
|
||||
if ((HashTable = (GifHashTableType *) malloc(sizeof(GifHashTableType)))
|
||||
== NULL)
|
||||
return NULL;
|
||||
|
||||
_ClearHashTable(HashTable);
|
||||
|
||||
return HashTable;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to clear the HashTable to an empty state. *
|
||||
This part is a little machine depended. Use the commented part otherwise. *
|
||||
******************************************************************************/
|
||||
void _ClearHashTable(GifHashTableType *HashTable)
|
||||
{
|
||||
memset(HashTable -> HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to insert a new Item into the HashTable. The data is assumed to be *
|
||||
new one. *
|
||||
******************************************************************************/
|
||||
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable -> HTable;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to test if given Key exists in HashTable and if so returns its code *
|
||||
Returns the Code if key was found, -1 if not. *
|
||||
******************************************************************************/
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable -> HTable, HTKey;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
if (Key == HTKey) return HT_GET_CODE(HTable[HKey]);
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to generate an HKey for the hashtable out of the given unique key. *
|
||||
The given Key is assumed to be 20 bits as follows: lower 8 bits are the *
|
||||
new postfix character, while the upper 12 bits are the prefix code. *
|
||||
Because the average hit ratio is only 2 (2 hash references per entry), *
|
||||
evaluating more complex keys (such as twin prime keys) does not worth it! *
|
||||
******************************************************************************/
|
||||
static int KeyItem(uint32_t Item)
|
||||
{
|
||||
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
/******************************************************************************
|
||||
Debugging routine to print the hit ratio - number of times the hash table *
|
||||
was tested per operation. This routine was used to test the KeyItem routine *
|
||||
******************************************************************************/
|
||||
void HashTablePrintHitRatio(void)
|
||||
{
|
||||
printf("Hash Table Hit Ratio is %ld/%ld = %ld%%.\n",
|
||||
NumberOfMisses, NumberOfTests,
|
||||
NumberOfMisses * 100 / NumberOfTests);
|
||||
}
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
/* end */
|
39
TMessagesProj/jni/giflib/gif_hash.h
Executable file
39
TMessagesProj/jni/giflib/gif_hash.h
Executable file
@ -0,0 +1,39 @@
|
||||
/******************************************************************************
|
||||
|
||||
gif_hash.h - magfic constants and declarations for GIF LZW
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _GIF_HASH_H_
|
||||
#define _GIF_HASH_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
|
||||
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
|
||||
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
|
||||
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
|
||||
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
|
||||
/* The 32 bits of the long are divided into two parts for the key & code: */
|
||||
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
|
||||
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
|
||||
/* The key is the upper 20 bits. The code is the lower 12. */
|
||||
#define HT_GET_KEY(l) (l >> 12)
|
||||
#define HT_GET_CODE(l) (l & 0x0FFF)
|
||||
#define HT_PUT_KEY(l) (l << 12)
|
||||
#define HT_PUT_CODE(l) (l & 0x0FFF)
|
||||
|
||||
typedef struct GifHashTableType {
|
||||
uint32_t HTable[HT_SIZE];
|
||||
} GifHashTableType;
|
||||
|
||||
GifHashTableType *_InitHashTable(void);
|
||||
void _ClearHashTable(GifHashTableType *HashTable);
|
||||
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code);
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key);
|
||||
|
||||
#endif /* _GIF_HASH_H_ */
|
||||
|
||||
/* end */
|
307
TMessagesProj/jni/giflib/gif_lib.h
Executable file
307
TMessagesProj/jni/giflib/gif_lib.h
Executable file
@ -0,0 +1,307 @@
|
||||
/******************************************************************************
|
||||
|
||||
gif_lib.h - service library for decoding and encoding GIF images
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_H_
|
||||
#define _GIF_LIB_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GIFLIB_MAJOR 5
|
||||
#define GIFLIB_MINOR 0
|
||||
#define GIFLIB_RELEASE 5
|
||||
|
||||
#define GIF_ERROR 0
|
||||
#define GIF_OK 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
|
||||
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char *GifRowType;
|
||||
typedef unsigned char GifByteType;
|
||||
typedef unsigned int GifPrefixType;
|
||||
typedef int GifWord;
|
||||
|
||||
typedef struct GifColorType {
|
||||
GifByteType Red, Green, Blue;
|
||||
} GifColorType;
|
||||
|
||||
typedef struct ColorMapObject {
|
||||
int ColorCount;
|
||||
int BitsPerPixel;
|
||||
bool SortFlag;
|
||||
GifColorType *Colors; /* on malloc(3) heap */
|
||||
} ColorMapObject;
|
||||
|
||||
typedef struct GifImageDesc {
|
||||
GifWord Left, Top, Width, Height; /* Current image dimensions. */
|
||||
bool Interlace; /* Sequential/Interlaced lines. */
|
||||
ColorMapObject *ColorMap; /* The local color map */
|
||||
} GifImageDesc;
|
||||
|
||||
typedef struct ExtensionBlock {
|
||||
int ByteCount;
|
||||
GifByteType *Bytes; /* on malloc(3) heap */
|
||||
int Function; /* The block function code */
|
||||
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
|
||||
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
|
||||
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
|
||||
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block */
|
||||
} ExtensionBlock;
|
||||
|
||||
typedef struct SavedImage {
|
||||
GifImageDesc ImageDesc;
|
||||
GifByteType *RasterBits; /* on malloc(3) heap */
|
||||
int ExtensionBlockCount; /* Count of extensions before image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
|
||||
} SavedImage;
|
||||
|
||||
typedef struct GifFileType {
|
||||
GifWord SWidth, SHeight; /* Size of virtual canvas */
|
||||
GifWord SColorResolution; /* How many colors can we generate? */
|
||||
GifWord SBackGroundColor; /* Background color for virtual canvas */
|
||||
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
|
||||
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
|
||||
int ImageCount; /* Number of current image (both APIs) */
|
||||
GifImageDesc Image; /* Current image (low-level API) */
|
||||
SavedImage *SavedImages; /* Image sequence (high-level API) */
|
||||
int ExtensionBlockCount; /* Count extensions past last image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
|
||||
int Error; /* Last error condition reported */
|
||||
void *UserData; /* hook to attach user data (TVT) */
|
||||
void *Private; /* Don't mess with this! */
|
||||
} GifFileType;
|
||||
|
||||
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED_RECORD_TYPE,
|
||||
SCREEN_DESC_RECORD_TYPE,
|
||||
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||
} GifRecordType;
|
||||
|
||||
/* func type to read gif data from arbitrary sources (TVT) */
|
||||
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
|
||||
|
||||
/* func type to write gif data to arbitrary targets.
|
||||
* Returns count of bytes written. (MRB)
|
||||
*/
|
||||
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
|
||||
|
||||
/******************************************************************************
|
||||
GIF89 structures
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct GraphicsControlBlock {
|
||||
int DisposalMode;
|
||||
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
|
||||
#define DISPOSE_DO_NOT 1 /* Leave image in place */
|
||||
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
|
||||
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
|
||||
bool UserInputFlag; /* User confirmation required before disposal */
|
||||
int DelayTime; /* pre-display delay in 0.01sec units */
|
||||
int TransparentColor; /* Palette index for transparency, -1 if none */
|
||||
#define NO_TRANSPARENT_COLOR -1
|
||||
} GraphicsControlBlock;
|
||||
|
||||
/******************************************************************************
|
||||
GIF encoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *EGifOpenFileName(const char *GifFileName,
|
||||
const bool GifTestExistence, int *Error);
|
||||
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
|
||||
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
|
||||
int EGifSpew(GifFileType * GifFile);
|
||||
char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
|
||||
int EGifCloseFile(GifFileType * GifFile);
|
||||
|
||||
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||
#define E_GIF_ERR_WRITE_FAILED 2
|
||||
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const int GifColorRes,
|
||||
const int GifBackGround,
|
||||
const ColorMapObject *GifColorMap);
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
const int GifLeft, const int GifTop,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const bool GifInterlace,
|
||||
const ColorMapObject *GifColorMap);
|
||||
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
|
||||
int GifLineLen);
|
||||
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
|
||||
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
|
||||
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
|
||||
int EGifPutExtensionBlock(GifFileType *GifFile,
|
||||
const int GifExtLen, const void *GifExtension);
|
||||
int EGifPutExtensionTrailer(GifFileType *GifFile);
|
||||
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
|
||||
const int GifExtLen,
|
||||
const void *GifExtension);
|
||||
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||
const GifByteType *GifCodeBlock);
|
||||
int EGifPutCodeNext(GifFileType *GifFile,
|
||||
const GifByteType *GifCodeBlock);
|
||||
|
||||
/******************************************************************************
|
||||
GIF decoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
|
||||
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
|
||||
int DGifSlurp(GifFileType * GifFile);
|
||||
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
|
||||
int DGifCloseFile(GifFileType * GifFile);
|
||||
|
||||
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||
#define D_GIF_ERR_READ_FAILED 102
|
||||
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||
#define D_GIF_ERR_WRONG_RECORD 107
|
||||
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||
#define D_GIF_ERR_NOT_READABLE 111
|
||||
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||
int DGifGetImageDesc(GifFileType *GifFile, bool changeImageCount);
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int DGifGetComment(GifFileType *GifFile, char *GifComment);
|
||||
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||
GifByteType **GifExtension);
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension,int* ExtCode);
|
||||
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||
GifByteType **GifCodeBlock);
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Color table quantization (deprecated)
|
||||
******************************************************************************/
|
||||
int GifQuantizeBuffer(unsigned int Width, unsigned int Height,
|
||||
int *ColorMapSize, GifByteType * RedInput,
|
||||
GifByteType * GreenInput, GifByteType * BlueInput,
|
||||
GifByteType * OutputBuffer,
|
||||
GifColorType * OutputColorMap);
|
||||
|
||||
/******************************************************************************
|
||||
Error handling and reporting.
|
||||
******************************************************************************/
|
||||
extern char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
|
||||
|
||||
/*****************************************************************************
|
||||
Everything below this point is new after version 1.2, supporting `slurp
|
||||
mode' for doing I/O in two big belts with all the image-bashing in core.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Color map handling from gif_alloc.c
|
||||
******************************************************************************/
|
||||
|
||||
extern ColorMapObject *GifMakeMapObject(int ColorCount,
|
||||
const GifColorType *ColorMap);
|
||||
extern void GifFreeMapObject(ColorMapObject *Object);
|
||||
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[]);
|
||||
extern int GifBitSize(int n);
|
||||
|
||||
/******************************************************************************
|
||||
Support for the in-core structures allocation (slurp mode).
|
||||
******************************************************************************/
|
||||
|
||||
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
|
||||
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len, unsigned char ExtData[]);
|
||||
extern void GifFreeExtensions(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks);
|
||||
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
|
||||
const SavedImage *CopyFrom);
|
||||
extern void GifFreeSavedImages(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
5.x functions for GIF89 graphics control blocks
|
||||
******************************************************************************/
|
||||
|
||||
int DGifExtensionToGCB(const size_t GifExtensionLength,
|
||||
const GifByteType *GifExtension,
|
||||
GraphicsControlBlock *GCB);
|
||||
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
|
||||
GifByteType *GifExtension);
|
||||
|
||||
int DGifSavedExtensionToGCB(GifFileType *GifFile,
|
||||
int ImageIndex,
|
||||
GraphicsControlBlock *GCB);
|
||||
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
|
||||
GifFileType *GifFile,
|
||||
int ImageIndex);
|
||||
|
||||
/******************************************************************************
|
||||
The library's internal utility font
|
||||
******************************************************************************/
|
||||
|
||||
#define GIF_FONT_WIDTH 8
|
||||
#define GIF_FONT_HEIGHT 8
|
||||
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
|
||||
|
||||
extern void GifDrawText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend, const int color);
|
||||
|
||||
extern void GifDrawBox(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawRectangle(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawBoxedText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int border, const int bg, const int fg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* _GIF_LIB_H */
|
||||
|
||||
/* end */
|
59
TMessagesProj/jni/giflib/gif_lib_private.h
Executable file
59
TMessagesProj/jni/giflib/gif_lib_private.h
Executable file
@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
|
||||
gif_lib_private.h - internal giflib routines and structures
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_PRIVATE_H
|
||||
#define _GIF_LIB_PRIVATE_H
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
|
||||
#define EXTENSION_INTRODUCER 0x21
|
||||
#define DESCRIPTOR_INTRODUCER 0x2c
|
||||
#define TERMINATOR_INTRODUCER 0x3b
|
||||
|
||||
#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
#define LZ_BITS 12
|
||||
|
||||
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
|
||||
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
|
||||
#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
|
||||
|
||||
#define FILE_STATE_WRITE 0x01
|
||||
#define FILE_STATE_SCREEN 0x02
|
||||
#define FILE_STATE_IMAGE 0x04
|
||||
#define FILE_STATE_READ 0x08
|
||||
|
||||
#define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ)
|
||||
#define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
|
||||
|
||||
typedef struct GifFilePrivateType {
|
||||
GifWord FileState, FileHandle, /* Where all this data goes to! */
|
||||
BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
|
||||
ClearCode, /* The CLEAR LZ code. */
|
||||
EOFCode, /* The EOF LZ code. */
|
||||
RunningCode, /* The next code algorithm can generate. */
|
||||
RunningBits, /* The number of bits required to represent RunningCode. */
|
||||
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
|
||||
LastCode, /* The code before the current code. */
|
||||
CrntCode, /* Current algorithm code. */
|
||||
StackPtr, /* For character stack (see below). */
|
||||
CrntShiftState; /* Number of bits in CrntShiftDWord. */
|
||||
unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
|
||||
unsigned long PixelCount; /* Number of pixels in image. */
|
||||
FILE *File; /* File as stream. */
|
||||
InputFunc Read; /* function to read gif input (TVT) */
|
||||
OutputFunc Write; /* function to write gif output (MRB) */
|
||||
GifByteType Buf[256]; /* Compressed input is buffered here. */
|
||||
GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
|
||||
GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
|
||||
GifPrefixType Prefix[LZ_MAX_CODE + 1];
|
||||
GifHashTableType *HashTable;
|
||||
bool gif89;
|
||||
} GifFilePrivateType;
|
||||
|
||||
#endif /* _GIF_LIB_PRIVATE_H */
|
||||
|
||||
/* end */
|
400
TMessagesProj/jni/giflib/gifalloc.c
Executable file
400
TMessagesProj/jni/giflib/gifalloc.c
Executable file
@ -0,0 +1,400 @@
|
||||
/*****************************************************************************
|
||||
|
||||
GIF construction tools
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
/******************************************************************************
|
||||
Miscellaneous utility functions
|
||||
******************************************************************************/
|
||||
|
||||
/* return smallest bitfield size n will fit in */
|
||||
int
|
||||
GifBitSize(int n)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 1; i <= 8; i++)
|
||||
if ((1 << i) >= n)
|
||||
break;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Color map object functions
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Allocate a color map of given size; initialize with contents of
|
||||
* ColorMap if that pointer is non-NULL.
|
||||
*/
|
||||
ColorMapObject *
|
||||
GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
|
||||
{
|
||||
ColorMapObject *Object;
|
||||
|
||||
/*** FIXME: Our ColorCount has to be a power of two. Is it necessary to
|
||||
* make the user know that or should we automatically round up instead? */
|
||||
if (ColorCount != (1 << GifBitSize(ColorCount))) {
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
|
||||
if (Object == (ColorMapObject *) NULL) {
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
|
||||
if (Object->Colors == (GifColorType *) NULL) {
|
||||
free(Object);
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object->ColorCount = ColorCount;
|
||||
Object->BitsPerPixel = GifBitSize(ColorCount);
|
||||
|
||||
if (ColorMap != NULL) {
|
||||
memcpy((char *)Object->Colors,
|
||||
(char *)ColorMap, ColorCount * sizeof(GifColorType));
|
||||
}
|
||||
|
||||
return (Object);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Free a color map object
|
||||
*******************************************************************************/
|
||||
void
|
||||
GifFreeMapObject(ColorMapObject *Object)
|
||||
{
|
||||
if (Object != NULL) {
|
||||
(void)free(Object->Colors);
|
||||
(void)free(Object);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DumpColorMap(ColorMapObject *Object,
|
||||
FILE * fp)
|
||||
{
|
||||
if (Object != NULL) {
|
||||
int i, j, Len = Object->ColorCount;
|
||||
|
||||
for (i = 0; i < Len; i += 4) {
|
||||
for (j = 0; j < 4 && j < Len; j++) {
|
||||
(void)fprintf(fp, "%3d: %02x %02x %02x ", i + j,
|
||||
Object->Colors[i + j].Red,
|
||||
Object->Colors[i + j].Green,
|
||||
Object->Colors[i + j].Blue);
|
||||
}
|
||||
(void)fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*******************************************************************************
|
||||
Compute the union of two given color maps and return it. If result can't
|
||||
fit into 256 colors, NULL is returned, the allocated union otherwise.
|
||||
ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
|
||||
copied iff they didn't exist before. ColorTransIn2 maps the old
|
||||
ColorIn2 into the ColorUnion color map table./
|
||||
*******************************************************************************/
|
||||
ColorMapObject *
|
||||
GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[])
|
||||
{
|
||||
int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
|
||||
ColorMapObject *ColorUnion;
|
||||
|
||||
/*
|
||||
* We don't worry about duplicates within either color map; if
|
||||
* the caller wants to resolve those, he can perform unions
|
||||
* with an empty color map.
|
||||
*/
|
||||
|
||||
/* Allocate table which will hold the result for sure. */
|
||||
ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
|
||||
ColorIn2->ColorCount) * 2, NULL);
|
||||
|
||||
if (ColorUnion == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Copy ColorIn1 to ColorUnion.
|
||||
*/
|
||||
for (i = 0; i < ColorIn1->ColorCount; i++)
|
||||
ColorUnion->Colors[i] = ColorIn1->Colors[i];
|
||||
CrntSlot = ColorIn1->ColorCount;
|
||||
|
||||
/*
|
||||
* Potentially obnoxious hack:
|
||||
*
|
||||
* Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
|
||||
* of table 1. This is very useful if your display is limited to
|
||||
* 16 colors.
|
||||
*/
|
||||
while (ColorIn1->Colors[CrntSlot - 1].Red == 0
|
||||
&& ColorIn1->Colors[CrntSlot - 1].Green == 0
|
||||
&& ColorIn1->Colors[CrntSlot - 1].Blue == 0)
|
||||
CrntSlot--;
|
||||
|
||||
/* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
|
||||
for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
|
||||
/* Let's see if this color already exists: */
|
||||
for (j = 0; j < ColorIn1->ColorCount; j++)
|
||||
if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
|
||||
sizeof(GifColorType)) == 0)
|
||||
break;
|
||||
|
||||
if (j < ColorIn1->ColorCount)
|
||||
ColorTransIn2[i] = j; /* color exists in Color1 */
|
||||
else {
|
||||
/* Color is new - copy it to a new slot: */
|
||||
ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
|
||||
ColorTransIn2[i] = CrntSlot++;
|
||||
}
|
||||
}
|
||||
|
||||
if (CrntSlot > 256) {
|
||||
GifFreeMapObject(ColorUnion);
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
NewGifBitSize = GifBitSize(CrntSlot);
|
||||
RoundUpTo = (1 << NewGifBitSize);
|
||||
|
||||
if (RoundUpTo != ColorUnion->ColorCount) {
|
||||
register GifColorType *Map = ColorUnion->Colors;
|
||||
|
||||
/*
|
||||
* Zero out slots up to next power of 2.
|
||||
* We know these slots exist because of the way ColorUnion's
|
||||
* start dimension was computed.
|
||||
*/
|
||||
for (j = CrntSlot; j < RoundUpTo; j++)
|
||||
Map[j].Red = Map[j].Green = Map[j].Blue = 0;
|
||||
|
||||
/* perhaps we can shrink the map? */
|
||||
if (RoundUpTo < ColorUnion->ColorCount)
|
||||
ColorUnion->Colors = (GifColorType *)realloc(Map,
|
||||
sizeof(GifColorType) * RoundUpTo);
|
||||
}
|
||||
|
||||
ColorUnion->ColorCount = RoundUpTo;
|
||||
ColorUnion->BitsPerPixel = NewGifBitSize;
|
||||
|
||||
return (ColorUnion);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Apply a given color translation to the raster bits of an image
|
||||
*******************************************************************************/
|
||||
void
|
||||
GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
|
||||
{
|
||||
register int i;
|
||||
register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
|
||||
|
||||
for (i = 0; i < RasterSize; i++)
|
||||
Image->RasterBits[i] = Translation[Image->RasterBits[i]];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Extension record functions
|
||||
******************************************************************************/
|
||||
int
|
||||
GifAddExtensionBlock(int *ExtensionBlockCount,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len,
|
||||
unsigned char ExtData[])
|
||||
{
|
||||
ExtensionBlock *ep;
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
*ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
|
||||
else
|
||||
*ExtensionBlocks = (ExtensionBlock *)realloc(*ExtensionBlocks,
|
||||
sizeof(ExtensionBlock) *
|
||||
(*ExtensionBlockCount + 1));
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
return (GIF_ERROR);
|
||||
|
||||
ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
|
||||
|
||||
ep->Function = Function;
|
||||
ep->ByteCount=Len;
|
||||
ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
|
||||
if (ep->Bytes == NULL)
|
||||
return (GIF_ERROR);
|
||||
|
||||
if (ExtData != NULL) {
|
||||
memcpy(ep->Bytes, ExtData, Len);
|
||||
}
|
||||
|
||||
return (GIF_OK);
|
||||
}
|
||||
|
||||
void
|
||||
GifFreeExtensions(int *ExtensionBlockCount,
|
||||
ExtensionBlock **ExtensionBlocks)
|
||||
{
|
||||
ExtensionBlock *ep;
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
return;
|
||||
|
||||
for (ep = *ExtensionBlocks;
|
||||
ep < (*ExtensionBlocks + *ExtensionBlockCount);
|
||||
ep++)
|
||||
(void)free((char *)ep->Bytes);
|
||||
(void)free((char *)*ExtensionBlocks);
|
||||
*ExtensionBlocks = NULL;
|
||||
*ExtensionBlockCount = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Image block allocation functions
|
||||
******************************************************************************/
|
||||
|
||||
/* Private Function:
|
||||
* Frees the last image in the GifFile->SavedImages array
|
||||
*/
|
||||
void
|
||||
FreeLastSavedImage(GifFileType *GifFile)
|
||||
{
|
||||
SavedImage *sp;
|
||||
|
||||
if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
|
||||
return;
|
||||
|
||||
/* Remove one SavedImage from the GifFile */
|
||||
GifFile->ImageCount--;
|
||||
sp = &GifFile->SavedImages[GifFile->ImageCount];
|
||||
|
||||
/* Deallocate its Colormap */
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||
sp->ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
|
||||
/* Deallocate the image data */
|
||||
if (sp->RasterBits != NULL)
|
||||
free((char *)sp->RasterBits);
|
||||
|
||||
/* Deallocate any extensions */
|
||||
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||
|
||||
/*** FIXME: We could realloc the GifFile->SavedImages structure but is
|
||||
* there a point to it? Saves some memory but we'd have to do it every
|
||||
* time. If this is used in GifFreeSavedImages then it would be inefficient
|
||||
* (The whole array is going to be deallocated.) If we just use it when
|
||||
* we want to free the last Image it's convenient to do it here.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Append an image block to the SavedImages array
|
||||
*/
|
||||
SavedImage *
|
||||
GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
|
||||
{
|
||||
if (GifFile->SavedImages == NULL)
|
||||
GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
||||
else
|
||||
GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
|
||||
sizeof(SavedImage) * (GifFile->ImageCount + 1));
|
||||
|
||||
if (GifFile->SavedImages == NULL)
|
||||
return ((SavedImage *)NULL);
|
||||
else {
|
||||
SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
|
||||
memset((char *)sp, '\0', sizeof(SavedImage));
|
||||
|
||||
if (CopyFrom != NULL) {
|
||||
memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
|
||||
|
||||
/*
|
||||
* Make our own allocated copies of the heap fields in the
|
||||
* copied record. This guards against potential aliasing
|
||||
* problems.
|
||||
*/
|
||||
|
||||
/* first, the local color map */
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
sp->ImageDesc.ColorMap = GifMakeMapObject(
|
||||
CopyFrom->ImageDesc.ColorMap->ColorCount,
|
||||
CopyFrom->ImageDesc.ColorMap->Colors);
|
||||
if (sp->ImageDesc.ColorMap == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* next, the raster */
|
||||
sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
|
||||
CopyFrom->ImageDesc.Height *
|
||||
CopyFrom->ImageDesc.Width);
|
||||
if (sp->RasterBits == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
memcpy(sp->RasterBits, CopyFrom->RasterBits,
|
||||
sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
|
||||
CopyFrom->ImageDesc.Width);
|
||||
|
||||
/* finally, the extension blocks */
|
||||
if (sp->ExtensionBlocks != NULL) {
|
||||
sp->ExtensionBlocks = (ExtensionBlock *)malloc(
|
||||
sizeof(ExtensionBlock) *
|
||||
CopyFrom->ExtensionBlockCount);
|
||||
if (sp->ExtensionBlocks == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
|
||||
sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
|
||||
}
|
||||
}
|
||||
|
||||
return (sp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GifFreeSavedImages(GifFileType *GifFile)
|
||||
{
|
||||
SavedImage *sp;
|
||||
|
||||
if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
|
||||
return;
|
||||
}
|
||||
for (sp = GifFile->SavedImages;
|
||||
sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||
sp->ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
|
||||
if (sp->RasterBits != NULL)
|
||||
free((char *)sp->RasterBits);
|
||||
|
||||
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||
}
|
||||
free((char *)GifFile->SavedImages);
|
||||
GifFile->SavedImages = NULL;
|
||||
}
|
||||
|
||||
/* end */
|
@ -3,9 +3,32 @@
|
||||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <android/log.h>
|
||||
#include "aes.h"
|
||||
#include "log.h"
|
||||
#include <stdlib.h>
|
||||
#include "aes/aes.h"
|
||||
#include "utils.h"
|
||||
#include "sqlite.h"
|
||||
#include "gif.h"
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sqliteOnJNILoad(vm, reserved, env) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gifOnJNILoad(vm, reserved, env);
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
gifOnJNIUnload(vm, reserved);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jbyteArray _what, jbyteArray _key, jbyteArray _iv, jboolean encrypt, jboolean changeIv, jint l) {
|
||||
unsigned char *what = (unsigned char *)(*env)->GetByteArrayElements(env, _what, NULL);
|
||||
|
@ -1,9 +0,0 @@
|
||||
#ifndef __SQLITE_H__
|
||||
#define __SQLITE_H__
|
||||
|
||||
#include <jni.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
void throw_sqlite3_exception(JNIEnv* env, sqlite3 *handle, int errcode);
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#include "sqlite3.h"
|
||||
#include "org_telegram_SQLite.h"
|
||||
#include "sqlite/sqlite3.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
void throw_sqlite3_exception(JNIEnv *env, sqlite3 *handle, int errcode) {
|
||||
if (SQLITE_OK == errcode) {
|
10
TMessagesProj/jni/sqlite.h
Executable file
10
TMessagesProj/jni/sqlite.h
Executable file
@ -0,0 +1,10 @@
|
||||
#ifndef sqlite_h
|
||||
#define sqlite_h
|
||||
|
||||
#include <jni.h>
|
||||
#include "sqlite/sqlite3.h"
|
||||
|
||||
void throw_sqlite3_exception(JNIEnv* env, sqlite3 *handle, int errcode);
|
||||
jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env);
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
#include "org_telegram_SQLite.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
int Java_org_telegram_SQLite_SQLiteCursor_columnType(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
@ -1,4 +1,4 @@
|
||||
#include "org_telegram_SQLite.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
void Java_org_telegram_SQLite_SQLiteDatabase_closedb(JNIEnv *env, jobject object, int sqliteHandle) {
|
||||
sqlite3 *handle = (sqlite3 *)sqliteHandle;
|
@ -1,20 +1,10 @@
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include "org_telegram_SQLite.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
jfieldID queryArgsCountField;
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv* env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
|
||||
jclass class = (*env)->FindClass(env, "org/telegram/SQLite/SQLitePreparedStatement");
|
||||
queryArgsCountField = (*env)->GetFieldID(env, class, "queryArgsCount", "I");
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
@ -9,4 +9,11 @@
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
#ifndef max
|
||||
#define max(x, y) ((x) > (y)) ? (x) : (y)
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,18 +0,0 @@
|
||||
#include <jni.h>
|
||||
#include "video.h"
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_VideoTools_initialize(JNIEnv* env, jclass class) {
|
||||
av_register_all();
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_VideoTools_convert(JNIEnv* env, jclass class, jstring in, jstring out, int bitr) {
|
||||
char const *in_str = (*env)->GetStringUTFChars(env, in, 0);
|
||||
char const *out_str = (*env)->GetStringUTFChars(env, out, 0);
|
||||
convertFile(in_str, out_str, bitr);
|
||||
if (in_str != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, in, in_str);
|
||||
}
|
||||
if (out_str != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, out, out_str);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#ifndef video_h
|
||||
#define video_h
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
int prepare_for_video_conversion(const char *dst_filename, AVCodecContext *video_dec_ctx, AVCodecContext *audio_dec_ctx, AVFormatContext *fmt_ctx, AVStream *src_video_stream, AVStream *src_audio_stream, int bitr);
|
||||
int write_video_frame(AVFrame *src_frame);
|
||||
int write_audio_frame(AVFrame *src_frame, AVCodecContext *src_codec);
|
||||
void post_video_conversion();
|
||||
void cleanup_out();
|
||||
void onError();
|
||||
void onProgress();
|
||||
void onDone();
|
||||
|
||||
void convertFile(const char *src_filename, const char *dst_filename, int bitr);
|
||||
|
||||
#endif
|
@ -1,243 +0,0 @@
|
||||
#include "video.h"
|
||||
#include <stdio.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include "log.h"
|
||||
|
||||
AVPacket pkt;
|
||||
int video_stream_idx = -1, audio_stream_idx = -1;
|
||||
AVCodecContext *video_dec_ctx = NULL, *audio_dec_ctx = NULL;
|
||||
AVFrame *frame = NULL;
|
||||
AVStream *video_stream = NULL, *audio_stream = NULL;
|
||||
AVFormatContext *fmt_ctx = NULL;
|
||||
int64_t total_duration;
|
||||
int64_t current_duration;
|
||||
char *src = NULL;
|
||||
char *dest = NULL;
|
||||
int lastLog = 10;
|
||||
|
||||
void cleanup_in() {
|
||||
if (video_dec_ctx) {
|
||||
avcodec_close(video_dec_ctx);
|
||||
video_dec_ctx = NULL;
|
||||
}
|
||||
if (audio_dec_ctx) {
|
||||
avcodec_close(audio_dec_ctx);
|
||||
audio_dec_ctx = NULL;
|
||||
}
|
||||
if (fmt_ctx) {
|
||||
avformat_close_input(&fmt_ctx);
|
||||
fmt_ctx = NULL;
|
||||
}
|
||||
if (frame) {
|
||||
av_frame_free(&frame);
|
||||
frame = NULL;
|
||||
}
|
||||
if (src) {
|
||||
free(src);
|
||||
src = NULL;
|
||||
}
|
||||
if (dest) {
|
||||
free(dest);
|
||||
dest = NULL;
|
||||
}
|
||||
|
||||
total_duration = 0;
|
||||
current_duration = 0;
|
||||
video_stream_idx = -1;
|
||||
audio_stream_idx = -1;
|
||||
video_stream = NULL;
|
||||
audio_stream = NULL;
|
||||
lastLog = 10;
|
||||
}
|
||||
|
||||
void onError() {
|
||||
cleanup_in();
|
||||
cleanup_out();
|
||||
}
|
||||
|
||||
void onDone() {
|
||||
LOGD("OK\n");
|
||||
cleanup_in();
|
||||
cleanup_out();
|
||||
}
|
||||
|
||||
void onProgress() {
|
||||
float progress = (float)current_duration / (float)total_duration * 100;
|
||||
if (progress > lastLog) {
|
||||
lastLog += 10;
|
||||
LOGD("progress %.2f\n", progress);
|
||||
}
|
||||
}
|
||||
|
||||
int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
|
||||
int ret;
|
||||
AVStream *st;
|
||||
AVCodecContext *dec_ctx = NULL;
|
||||
AVCodec *dec = NULL;
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not find %s stream in input file\n", av_get_media_type_string(type));
|
||||
return ret;
|
||||
} else {
|
||||
*stream_idx = ret;
|
||||
st = fmt_ctx->streams[*stream_idx];
|
||||
|
||||
dec_ctx = st->codec;
|
||||
dec = avcodec_find_decoder(dec_ctx->codec_id);
|
||||
if (!dec) {
|
||||
LOGD("Failed to find %s codec\n", av_get_media_type_string(type));
|
||||
return ret;
|
||||
}
|
||||
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
|
||||
LOGD("Failed to open %s codec\n", av_get_media_type_string(type));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decode_packet(int *got_frame, int cached) {
|
||||
int ret = 0;
|
||||
int decoded = pkt.size;
|
||||
|
||||
*got_frame = 0;
|
||||
|
||||
if (pkt.stream_index == video_stream_idx) {
|
||||
ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
|
||||
if (ret < 0) {
|
||||
LOGD("Error decoding video frame\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (*got_frame) {
|
||||
ret = write_video_frame(frame);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else if (pkt.stream_index == audio_stream_idx) {
|
||||
ret = avcodec_decode_audio4(audio_dec_ctx, frame, got_frame, &pkt);
|
||||
|
||||
if (ret < 0) {
|
||||
LOGD("Error decoding audio frame\n");
|
||||
return ret;
|
||||
}
|
||||
decoded = FFMIN(ret, pkt.size);
|
||||
|
||||
if (*got_frame) {
|
||||
ret = write_audio_frame(frame, audio_dec_ctx);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
frame->pts = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
if (*got_frame) {
|
||||
av_frame_unref(frame);
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
void convertFile(const char *src_filename, const char *dst_filename, int bitr) {
|
||||
int ret = 0;
|
||||
int got_frame;
|
||||
|
||||
src = malloc(strlen(src_filename) + 1);
|
||||
memcpy(src, src_filename, strlen(src_filename));
|
||||
src[strlen(src_filename)] = '\0';
|
||||
dest = malloc(strlen(dst_filename) + 1);
|
||||
memcpy(dest, dst_filename, strlen(dst_filename));
|
||||
dest[strlen(dst_filename)] = '\0';
|
||||
|
||||
if ((ret = avformat_open_input(&fmt_ctx, src, NULL, NULL)) < 0) {
|
||||
LOGD("Could not open source file %s, %s\n", src, av_err2str(ret));
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
|
||||
LOGD("Could not find stream information\n");
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
|
||||
video_stream = fmt_ctx->streams[video_stream_idx];
|
||||
video_dec_ctx = video_stream->codec;
|
||||
}
|
||||
|
||||
if (open_codec_context(&audio_stream_idx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
|
||||
audio_stream = fmt_ctx->streams[audio_stream_idx];
|
||||
audio_dec_ctx = audio_stream->codec;
|
||||
}
|
||||
|
||||
av_dump_format(fmt_ctx, 0, src, 0);
|
||||
|
||||
if (!audio_stream && !video_stream) {
|
||||
LOGD("Could not find audio or video stream in the input, aborting\n");
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
LOGD("Could not allocate frame\n");
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
|
||||
if (video_stream) {
|
||||
LOGD("Demuxing video from file '%s'\n", src);
|
||||
}
|
||||
if (audio_stream) {
|
||||
LOGD("Demuxing audio from file '%s'\n", src);
|
||||
}
|
||||
|
||||
ret = prepare_for_video_conversion(dest, video_dec_ctx, audio_dec_ctx, fmt_ctx, video_stream, audio_stream, bitr);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
if (video_stream) {
|
||||
total_duration = video_stream->duration;
|
||||
}
|
||||
if (audio_stream) {
|
||||
total_duration += audio_stream->duration;
|
||||
}
|
||||
|
||||
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
|
||||
AVPacket orig_pkt = pkt;
|
||||
do {
|
||||
ret = decode_packet(&got_frame, 0);
|
||||
if (ret < 0) {
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
pkt.data += ret;
|
||||
pkt.size -= ret;
|
||||
current_duration += pkt.duration;
|
||||
onProgress();
|
||||
} while (pkt.size > 0);
|
||||
av_free_packet(&orig_pkt);
|
||||
}
|
||||
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
do {
|
||||
decode_packet(&got_frame, 1);
|
||||
} while (got_frame);
|
||||
|
||||
post_video_conversion();
|
||||
onDone();
|
||||
}
|
@ -1,366 +0,0 @@
|
||||
#include "video.h"
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
#include "log.h"
|
||||
|
||||
AVFrame *out_frame = NULL;
|
||||
struct SwsContext *sws_ctx = NULL;
|
||||
AVStream *video_st = NULL, *audio_st = NULL;
|
||||
AVFormatContext *oc = NULL;
|
||||
AVOutputFormat *fmt = NULL;
|
||||
AVPicture dst_picture;
|
||||
|
||||
uint8_t **dst_samples_data = NULL;
|
||||
SwrContext *swr_ctx = NULL;
|
||||
|
||||
int current_n_out = 0;
|
||||
int current_in_buff = 0;
|
||||
uint8_t buff[4096 * 2];
|
||||
|
||||
int min(int val1, int val2) {
|
||||
return val1 < val2 ? val1 : val2;
|
||||
}
|
||||
|
||||
int prepare_for_video_conversion(const char *dst_filename, AVCodecContext *video_dec_ctx, AVCodecContext *audio_dec_ctx, AVFormatContext *fmt_ctx, AVStream *src_video_stream, AVStream *src_audio_stream, int bitr) {
|
||||
|
||||
if (!video_dec_ctx && !audio_dec_ctx) {
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
avformat_alloc_output_context2(&oc, NULL, "mp4", dst_filename);
|
||||
if (!oc) {
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
fmt = oc->oformat;
|
||||
av_dict_copy(&oc->metadata, fmt_ctx->metadata, 0);
|
||||
|
||||
int ret = 0;
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&oc->pb, dst_filename, AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not open '%s': %s\n", dst_filename, av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
AVCodecContext *c;
|
||||
|
||||
if (video_dec_ctx && src_video_stream && fmt_ctx) {
|
||||
//calculate video resolution
|
||||
int dst_width = video_dec_ctx->width, dst_height = video_dec_ctx->height;
|
||||
if (video_dec_ctx->width > video_dec_ctx->height) {
|
||||
if (video_dec_ctx->width > 480) {
|
||||
float scale = video_dec_ctx->width / 480.0f;
|
||||
dst_width = 480;
|
||||
dst_height = ceilf(video_dec_ctx->height / scale);
|
||||
}
|
||||
} else {
|
||||
if (video_dec_ctx->width > 480) {
|
||||
float scale = video_dec_ctx->height / 480.0f;
|
||||
dst_height = 480;
|
||||
dst_width = ceilf(video_dec_ctx->width / scale);
|
||||
}
|
||||
}
|
||||
if (video_dec_ctx->height != dst_height || video_dec_ctx->width != dst_width || video_dec_ctx->pix_fmt != AV_PIX_FMT_YUV420P) {
|
||||
sws_ctx = sws_getContext(video_dec_ctx->width, video_dec_ctx->height, video_dec_ctx->pix_fmt, dst_width, dst_height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
if (!sws_ctx) {
|
||||
LOGD("Could not initialize the conversion context\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//create video stream
|
||||
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
|
||||
if (!codec) {
|
||||
LOGD("Could not find encoder for '%s'\n", avcodec_get_name(AV_CODEC_ID_MPEG4));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
video_st = avformat_new_stream(oc, codec);
|
||||
if (!video_st) {
|
||||
LOGD("Could not allocate stream\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
video_st->id = oc->nb_streams - 1;
|
||||
av_dict_copy(&video_st->metadata, src_video_stream->metadata, 0);
|
||||
c = video_st->codec;
|
||||
c->codec_id = AV_CODEC_ID_MPEG4;
|
||||
c->bit_rate = bitr;
|
||||
c->width = dst_width;
|
||||
c->height = dst_height;
|
||||
double fps = (double)src_video_stream->avg_frame_rate.num / (double)src_video_stream->avg_frame_rate.den;
|
||||
c->time_base.den = 65535;
|
||||
c->time_base.num = floor(65635 / fps);
|
||||
c->gop_size = 12;
|
||||
c->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
ret = avcodec_open2(c, codec, NULL);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not open video codec: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_frame = avcodec_alloc_frame();
|
||||
if (!out_frame) {
|
||||
LOGD("Could not allocate video frame\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not allocate picture: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
*((AVPicture *)out_frame) = dst_picture;
|
||||
}
|
||||
|
||||
//create audio stream
|
||||
if (audio_dec_ctx && src_audio_stream) {
|
||||
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
if (!codec) {
|
||||
LOGD("Could not find encoder for '%s'\n", avcodec_get_name(AV_CODEC_ID_AAC));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
audio_st = avformat_new_stream(oc, codec);
|
||||
if (!audio_st) {
|
||||
LOGD("Could not allocate stream\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
audio_st->id = oc->nb_streams - 1;
|
||||
av_dict_copy(&audio_st->metadata, src_audio_stream->metadata, 0);
|
||||
c = audio_st->codec;
|
||||
c->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
||||
c->bit_rate = 40000;
|
||||
c->sample_rate = min(audio_dec_ctx->sample_rate, 44100);
|
||||
c->channels = 1;
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
c = audio_st->codec;
|
||||
c->strict_std_compliance = -2;
|
||||
|
||||
swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_MONO, c->sample_fmt, c->sample_rate, audio_dec_ctx->channel_layout, audio_dec_ctx->sample_fmt, audio_dec_ctx->sample_rate, 0, NULL);
|
||||
if (!swr_ctx) {
|
||||
LOGD("Could not allocate resampler context\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||
LOGD("Failed to initialize the resampling context\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = avcodec_open2(c, codec, NULL);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not open audio codec: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
av_dump_format(oc, 0, dst_filename, 1);
|
||||
|
||||
ret = avformat_write_header(oc, NULL);
|
||||
if (ret < 0) {
|
||||
LOGD("Error occurred when opening output file: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out_frame) {
|
||||
out_frame->pts = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_out() {
|
||||
if (video_st) {
|
||||
avcodec_close(video_st->codec);
|
||||
if (dst_picture.data) {
|
||||
av_free(dst_picture.data[0]);
|
||||
}
|
||||
if (out_frame) {
|
||||
av_free(out_frame);
|
||||
out_frame = NULL;
|
||||
}
|
||||
video_st = NULL;
|
||||
}
|
||||
if (audio_st) {
|
||||
avcodec_close(audio_st->codec);
|
||||
if (dst_samples_data) {
|
||||
av_free(dst_samples_data[0]);
|
||||
dst_samples_data = NULL;
|
||||
}
|
||||
audio_st = NULL;
|
||||
}
|
||||
|
||||
if (fmt && !(fmt->flags & AVFMT_NOFILE)) {
|
||||
avio_close(oc->pb);
|
||||
fmt = NULL;
|
||||
}
|
||||
|
||||
if (oc) {
|
||||
avformat_free_context(oc);
|
||||
oc = NULL;
|
||||
}
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
sws_ctx = NULL;
|
||||
}
|
||||
if (swr_ctx) {
|
||||
swr_free(&swr_ctx);
|
||||
swr_ctx = NULL;
|
||||
}
|
||||
current_n_out = 0;
|
||||
current_in_buff = 0;
|
||||
}
|
||||
|
||||
int write_video_frame(AVFrame *src_frame) {
|
||||
int ret;
|
||||
|
||||
if (sws_ctx) {
|
||||
ret = sws_scale(sws_ctx, (const uint8_t * const *)src_frame->data, src_frame->linesize, 0, src_frame->height, out_frame->data, out_frame->linesize);
|
||||
if (ret < 0) {
|
||||
LOGD("scale error: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++){
|
||||
out_frame->data[i] = src_frame->data[i];
|
||||
out_frame->linesize[i] = src_frame->linesize[i];
|
||||
}
|
||||
}
|
||||
|
||||
AVPacket pkt = { 0 };
|
||||
int got_packet;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
ret = avcodec_encode_video2(video_st->codec, &pkt, out_frame, &got_packet);
|
||||
if (ret < 0) {
|
||||
LOGD("Error encoding video frame: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ret && got_packet && pkt.size) {
|
||||
pkt.stream_index = video_st->index;
|
||||
ret = av_interleaved_write_frame(oc, &pkt);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
LOGD("Error while writing video frame: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
int64_t val = av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
|
||||
out_frame->pts += val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_write_packet(int flush) {
|
||||
int got_packet, ret;
|
||||
int writed = 0;
|
||||
int dst_samples_size = av_samples_get_buffer_size(NULL, audio_st->codec->channels, audio_st->codec->frame_size, audio_st->codec->sample_fmt, 1);
|
||||
while (current_n_out > audio_st->codec->frame_size || (flush && current_n_out)) {
|
||||
AVFrame *frame = avcodec_alloc_frame();
|
||||
AVPacket pkt2 = { 0 };
|
||||
av_init_packet(&pkt2);
|
||||
|
||||
frame->nb_samples = min(audio_st->codec->frame_size, current_n_out);
|
||||
int nb_samples_size = min(dst_samples_size, current_in_buff);
|
||||
ret = avcodec_fill_audio_frame(frame, audio_st->codec->channels, audio_st->codec->sample_fmt, buff + writed, nb_samples_size, 1);
|
||||
|
||||
if (ret < 0) {
|
||||
LOGD("Error fill frame: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = avcodec_encode_audio2(audio_st->codec, &pkt2, frame, &got_packet);
|
||||
if (ret < 0) {
|
||||
LOGD("Error encoding audio frame: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (got_packet) {
|
||||
pkt2.stream_index = audio_st->index;
|
||||
ret = av_interleaved_write_frame(oc, &pkt2);
|
||||
if (ret != 0) {
|
||||
LOGD("Error while writing audio frame: %s\n", av_err2str(ret));
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
writed += dst_samples_size;
|
||||
current_n_out -= frame->nb_samples;
|
||||
current_in_buff -= nb_samples_size;
|
||||
avcodec_free_frame(&frame);
|
||||
}
|
||||
if (current_in_buff != 0 && writed != 0) {
|
||||
memcpy(buff, buff + writed, current_in_buff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_audio_frame(AVFrame *src_frame, AVCodecContext *src_codec) {
|
||||
const int n_in = src_frame->nb_samples;
|
||||
double ratio = (double)audio_st->codec->sample_rate / src_frame->sample_rate;
|
||||
int n_out = n_in * ratio + 32;
|
||||
int64_t delay = swr_get_delay(swr_ctx, audio_st->codec->sample_rate);
|
||||
if (delay > 0) {
|
||||
n_out += delay;
|
||||
}
|
||||
|
||||
if (!dst_samples_data) {
|
||||
int ret = av_samples_alloc_array_and_samples(&dst_samples_data, NULL, audio_st->codec->channels, n_out, audio_st->codec->sample_fmt, 0);
|
||||
if (ret < 0) {
|
||||
LOGD("Could not allocate destination samples\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
n_out = swr_convert(swr_ctx, dst_samples_data, n_out, (const uint8_t **)src_frame->extended_data, src_frame->nb_samples);
|
||||
if (n_out <= 0) {
|
||||
LOGD("Error while converting\n");
|
||||
onError();
|
||||
return -1;
|
||||
}
|
||||
int total_size = av_samples_get_buffer_size(NULL, audio_st->codec->channels, n_out, audio_st->codec->sample_fmt, 1);
|
||||
memcpy(buff + current_in_buff, dst_samples_data[0], total_size);
|
||||
current_n_out += n_out;
|
||||
current_in_buff += total_size;
|
||||
return check_write_packet(0);
|
||||
}
|
||||
|
||||
void post_video_conversion() {
|
||||
check_write_packet(1);
|
||||
av_write_trailer(oc);
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -27,11 +27,11 @@ package org.telegram.PhoneFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CallingCodeInfo {
|
||||
public ArrayList<String> countries;
|
||||
public String callingCode;
|
||||
public ArrayList<String> trunkPrefixes;
|
||||
public ArrayList<String> intlPrefixes;
|
||||
public ArrayList<RuleSet> ruleSets;
|
||||
public ArrayList<String> countries = new ArrayList<String>();
|
||||
public String callingCode = "";
|
||||
public ArrayList<String> trunkPrefixes = new ArrayList<String>();
|
||||
public ArrayList<String> intlPrefixes = new ArrayList<String>();
|
||||
public ArrayList<RuleSet> ruleSets = new ArrayList<RuleSet>();
|
||||
//public ArrayList formatStrings;
|
||||
|
||||
String matchingAccessCode(String str) {
|
||||
|
@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
public class RuleSet {
|
||||
public int matchLen;
|
||||
public ArrayList<PhoneRule> rules;
|
||||
public ArrayList<PhoneRule> rules = new ArrayList<PhoneRule>();
|
||||
public boolean hasRuleWithIntlPrefix;
|
||||
public boolean hasRuleWithTrunkPrefix;
|
||||
public static Pattern pattern = Pattern.compile("[0-9]+");
|
||||
|
@ -37,7 +37,7 @@ public class AwakeService extends Service {
|
||||
|
||||
public static void startService() {
|
||||
try {
|
||||
if (MessagesController.isScreenOn && ApplicationLoader.lastPauseTime == 0) {
|
||||
if (ApplicationLoader.isScreenOn && ApplicationLoader.lastPauseTime == 0) {
|
||||
return;
|
||||
}
|
||||
timeout = 10000;
|
||||
|
@ -649,7 +649,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
if (phone.startsWith("968")) {
|
||||
for (HashMap.Entry<Integer, Datacenter> entry : datacenters.entrySet()) {
|
||||
Datacenter datacenter = entry.getValue();
|
||||
datacenter.overridePort = 14;
|
||||
datacenter.overridePort = 8888;
|
||||
if (datacenter.connection != null) {
|
||||
datacenter.connection.suspendConnection(true);
|
||||
}
|
||||
@ -2041,13 +2041,14 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
if (request.serverFailureCount < 1) {
|
||||
discardResponse = true;
|
||||
request.runningMinStartTime = request.runningStartTime + 1;
|
||||
request.serverFailureCount++;
|
||||
}
|
||||
} else {
|
||||
discardResponse = true;
|
||||
request.runningMinStartTime = request.runningStartTime + 1;
|
||||
int delay = Math.min(1, request.serverFailureCount * 2);
|
||||
request.runningMinStartTime = request.runningStartTime + delay;
|
||||
request.confirmed = false;
|
||||
}
|
||||
request.serverFailureCount++;
|
||||
} else if (errorCode == 420) {
|
||||
if ((request.flags & RPCRequest.RPCRequestClassFailOnServerErrors) == 0) {
|
||||
double waitTime = 2.0;
|
||||
|
@ -323,19 +323,9 @@ public class ContactsController {
|
||||
name = PhoneFormat.getInstance().format(phone);
|
||||
}
|
||||
|
||||
String[] args = name.split(" ", 2);
|
||||
|
||||
Contact contact = new Contact();
|
||||
if (args.length > 0) {
|
||||
contact.first_name = args[0];
|
||||
} else {
|
||||
contact.first_name = "";
|
||||
}
|
||||
if (args.length > 1) {
|
||||
contact.last_name = args[1];
|
||||
} else {
|
||||
contact.first_name = name;
|
||||
contact.last_name = "";
|
||||
}
|
||||
contact.id = pCur.getInt(2);
|
||||
contactsMap.put(contact.id, contact);
|
||||
|
||||
|
@ -25,7 +25,7 @@ public class Datacenter {
|
||||
public ArrayList<String> addresses = new ArrayList<String>();
|
||||
public HashMap<String, Integer> ports = new HashMap<String, Integer>();
|
||||
public int[] defaultPorts = new int[] {-1, 80, -1, 443, -1, 443, -1, 80, -1, 443, -1};
|
||||
public int[] defaultPorts14 = new int[] {-1, 14, -1, 443, -1, 14, -1, 80, -1, 14, -1};
|
||||
public int[] defaultPorts8888 = new int[] {-1, 8888, -1, 443, -1, 8888, -1, 80, -1, 8888, -1};
|
||||
public boolean authorized;
|
||||
public long authSessionId;
|
||||
public long authDownloadSessionId;
|
||||
@ -136,8 +136,8 @@ public class Datacenter {
|
||||
|
||||
int[] portsArray = defaultPorts;
|
||||
|
||||
if (overridePort == 14) {
|
||||
portsArray = defaultPorts14;
|
||||
if (overridePort == 8888) {
|
||||
portsArray = defaultPorts8888;
|
||||
}
|
||||
|
||||
if (currentPortNum >= defaultPorts.length) {
|
||||
|
@ -198,7 +198,7 @@ public class FileLoadOperation {
|
||||
}
|
||||
final boolean dontDelete = isLocalFile;
|
||||
if ((exist = cacheFileFinal.exists()) && !ignoreCache) {
|
||||
Utilities.cacheOutQueue.postRunnable(new Runnable() {
|
||||
FileLoader.cacheOutQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@ -403,7 +403,7 @@ public class FileLoadOperation {
|
||||
final boolean renamed = cacheFileTemp.renameTo(cacheFileFinal);
|
||||
|
||||
if (needBitmapCreate) {
|
||||
Utilities.cacheOutQueue.postRunnable(new Runnable() {
|
||||
FileLoader.cacheOutQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int delay = 20;
|
||||
@ -520,7 +520,7 @@ public class FileLoadOperation {
|
||||
int readed = httpConnectionStream.read(data);
|
||||
if (readed > 0) {
|
||||
fileOutputStream.write(data, 0, readed);
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
FileLoader.fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startDownloadHTTPRequest();
|
||||
|
@ -38,6 +38,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class FileLoader {
|
||||
public LruCache memCache;
|
||||
|
||||
public static volatile DispatchQueue cacheOutQueue = new DispatchQueue("cacheOutQueue");
|
||||
public static volatile DispatchQueue fileLoaderQueue = new DispatchQueue("fileUploadQueue");
|
||||
|
||||
private String ignoreRemoval = null;
|
||||
private ConcurrentHashMap<String, CacheImage> imageLoading;
|
||||
private HashMap<Integer, CacheImage> imageLoadingByKeys;
|
||||
@ -50,9 +53,11 @@ public class FileLoader {
|
||||
private int currentUploadOperationsCount = 0;
|
||||
private Queue<FileLoadOperation> loadOperationQueue;
|
||||
private Queue<FileLoadOperation> audioLoadOperationQueue;
|
||||
private Queue<FileLoadOperation> photoLoadOperationQueue;
|
||||
private ConcurrentHashMap<String, FileLoadOperation> loadOperationPaths;
|
||||
private int currentLoadOperationsCount = 0;
|
||||
private int currentAudioLoadOperationsCount = 0;
|
||||
private int currentPhotoLoadOperationsCount = 0;
|
||||
public static long lastCacheOutTime = 0;
|
||||
public ConcurrentHashMap<String, Float> fileProgresses = new ConcurrentHashMap<String, Float>();
|
||||
private long lastProgressUpdateTime = 0;
|
||||
@ -108,21 +113,12 @@ public class FileLoader {
|
||||
try {
|
||||
Class cl = Class.forName("dalvik.system.VMRuntime");
|
||||
Method getRt = cl.getMethod("getRuntime", new Class[0]);
|
||||
runtime = getRt.invoke(null, new Object[0]);
|
||||
Object obj = new Object[0];
|
||||
runtime = getRt.invoke(null, obj);
|
||||
trackAllocation = cl.getMethod("trackExternalAllocation", new Class[] {long.class});
|
||||
trackFree = cl.getMethod("trackExternalFree", new Class[] {long.class});
|
||||
success = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} catch (SecurityException e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
FileLog.e("tmessages", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
if (!success) {
|
||||
@ -179,7 +175,7 @@ public class FileLoader {
|
||||
}
|
||||
}
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (imageViewArray) {
|
||||
@ -316,10 +312,11 @@ public class FileLoader {
|
||||
loadOperationPaths = new ConcurrentHashMap<String, FileLoadOperation>();
|
||||
loadOperationQueue = new LinkedList<FileLoadOperation>();
|
||||
audioLoadOperationQueue = new LinkedList<FileLoadOperation>();
|
||||
photoLoadOperationQueue = new LinkedList<FileLoadOperation>();
|
||||
}
|
||||
|
||||
public void cancelUploadFile(final String location, final boolean enc) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!enc) {
|
||||
@ -344,7 +341,7 @@ public class FileLoader {
|
||||
}
|
||||
|
||||
public void uploadFile(final String location, final byte[] key, final byte[] iv) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (key != null) {
|
||||
@ -365,7 +362,7 @@ public class FileLoader {
|
||||
operation.delegate = new FileUploadOperation.FileUploadOperationDelegate() {
|
||||
@Override
|
||||
public void didFinishUploadingFile(FileUploadOperation operation, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@ -394,7 +391,7 @@ public class FileLoader {
|
||||
|
||||
@Override
|
||||
public void didFailedUploadingFile(final FileUploadOperation operation) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@ -454,7 +451,7 @@ public class FileLoader {
|
||||
if (video == null && photo == null && document == null && audio == null) {
|
||||
return;
|
||||
}
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String fileName = null;
|
||||
@ -474,6 +471,8 @@ public class FileLoader {
|
||||
if (operation != null) {
|
||||
if (audio != null) {
|
||||
audioLoadOperationQueue.remove(operation);
|
||||
} else if (photo != null) {
|
||||
photoLoadOperationQueue.remove(operation);
|
||||
} else {
|
||||
loadOperationQueue.remove(operation);
|
||||
}
|
||||
@ -488,7 +487,7 @@ public class FileLoader {
|
||||
}
|
||||
|
||||
public void loadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo, final TLRPC.Document document, final TLRPC.Audio audio) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String fileName = null;
|
||||
@ -540,7 +539,7 @@ public class FileLoader {
|
||||
NotificationCenter.getInstance().postNotificationName(FileDidLoaded, arg1);
|
||||
}
|
||||
});
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadOperationPaths.remove(arg1);
|
||||
@ -553,6 +552,15 @@ public class FileLoader {
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
} else if (photo != null) {
|
||||
currentPhotoLoadOperationsCount--;
|
||||
if (currentPhotoLoadOperationsCount < 2) {
|
||||
FileLoadOperation operation = photoLoadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentPhotoLoadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentLoadOperationsCount--;
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
@ -579,7 +587,7 @@ public class FileLoader {
|
||||
}
|
||||
});
|
||||
}
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadOperationPaths.remove(arg1);
|
||||
@ -592,6 +600,15 @@ public class FileLoader {
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
} else if (photo != null) {
|
||||
currentPhotoLoadOperationsCount--;
|
||||
if (currentPhotoLoadOperationsCount < 2) {
|
||||
FileLoadOperation operation = photoLoadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentPhotoLoadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentLoadOperationsCount--;
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
@ -630,6 +647,13 @@ public class FileLoader {
|
||||
} else {
|
||||
audioLoadOperationQueue.add(operation);
|
||||
}
|
||||
} else if (photo != null) {
|
||||
if (currentPhotoLoadOperationsCount < 2) {
|
||||
currentPhotoLoadOperationsCount++;
|
||||
operation.start();
|
||||
} else {
|
||||
photoLoadOperationQueue.add(operation);
|
||||
}
|
||||
} else {
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
currentLoadOperationsCount++;
|
||||
@ -674,7 +698,7 @@ public class FileLoader {
|
||||
if (imageView == null) {
|
||||
return;
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Integer TAG = getTag(imageView);
|
||||
@ -776,14 +800,16 @@ public class FileLoader {
|
||||
if ((url == null && httpUrl == null) || imageView == null || (url != null && !(url instanceof TLRPC.TL_fileLocation) && !(url instanceof TLRPC.TL_fileEncryptedLocation))) {
|
||||
return;
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String key;
|
||||
String fileName = null;
|
||||
if (httpUrl != null) {
|
||||
key = Utilities.MD5(httpUrl);
|
||||
} else {
|
||||
key = url.volume_id + "_" + url.local_id;
|
||||
fileName = key + ".jpg";
|
||||
}
|
||||
if (filter != null) {
|
||||
key += "@" + filter;
|
||||
@ -832,6 +858,7 @@ public class FileLoader {
|
||||
imageLoading.put(key, img);
|
||||
|
||||
final String arg2 = key;
|
||||
final String arg3 = fileName;
|
||||
FileLoadOperation loadOperation;
|
||||
if (httpUrl != null) {
|
||||
loadOperation = new FileLoadOperation(httpUrl);
|
||||
@ -843,30 +870,43 @@ public class FileLoader {
|
||||
loadOperation.delegate = new FileLoadOperation.FileLoadOperationDelegate() {
|
||||
@Override
|
||||
public void didFinishLoadingFile(final FileLoadOperation operation) {
|
||||
enqueueImageProcessingOperationWithImage(operation.image, filter, arg2, img);
|
||||
if (operation.totalBytesCount != 0) {
|
||||
final String arg1 = operation.location.volume_id + "_" + operation.location.local_id + ".jpg";
|
||||
fileProgresses.remove(arg1);
|
||||
fileProgresses.remove(arg3);
|
||||
}
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (arg3 != null) {
|
||||
loadOperationPaths.remove(arg3);
|
||||
}
|
||||
for (Object v : img.imageViewArray) {
|
||||
imageLoadingByKeys.remove(getTag(v));
|
||||
}
|
||||
checkOperationsAndClear(img.loadOperation);
|
||||
imageLoading.remove(arg2);
|
||||
}
|
||||
});
|
||||
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.getInstance().postNotificationName(FileLoadProgressChanged, arg1, 1.0f);
|
||||
img.callAndClear(operation.image);
|
||||
if (operation.image != null && memCache.get(arg2) == null) {
|
||||
memCache.put(arg2, operation.image);
|
||||
}
|
||||
NotificationCenter.getInstance().postNotificationName(FileDidLoaded, arg3);
|
||||
}
|
||||
});
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.getInstance().postNotificationName(FileDidLoaded, arg1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFailedLoadingFile(final FileLoadOperation operation) {
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
fileLoaderQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (arg3 != null) {
|
||||
loadOperationPaths.remove(arg3);
|
||||
}
|
||||
for (Object view : img.imageViewArray) {
|
||||
imageLoadingByKeys.remove(getTag(view));
|
||||
imageLoading.remove(arg2);
|
||||
@ -921,6 +961,9 @@ public class FileLoader {
|
||||
} else {
|
||||
operationsQueue.add(loadOperation);
|
||||
}
|
||||
if (fileName != null) {
|
||||
loadOperationPaths.put(fileName, loadOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -936,85 +979,6 @@ public class FileLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public void processImage(Bitmap image, Object imageView, String filter, boolean cancel) {
|
||||
if (filter == null || imageView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Integer TAG = getTag(imageView);
|
||||
if (TAG == null) {
|
||||
TAG = lastImageNum;
|
||||
setTag(image, TAG);
|
||||
lastImageNum++;
|
||||
if (lastImageNum == Integer.MAX_VALUE)
|
||||
lastImageNum = 0;
|
||||
}
|
||||
|
||||
boolean added = false;
|
||||
boolean addToByKeys = true;
|
||||
CacheImage alreadyLoadingImage = imageLoading.get(filter);
|
||||
if (cancel) {
|
||||
CacheImage ei = imageLoadingByKeys.get(TAG);
|
||||
if (ei != null) {
|
||||
if (ei != alreadyLoadingImage) {
|
||||
ei.removeImageView(imageView);
|
||||
if (ei.imageViewArray.size() == 0) {
|
||||
checkOperationsAndClear(ei.loadOperation);
|
||||
ei.cancelAndClear();
|
||||
imageLoading.remove(ei.key);
|
||||
}
|
||||
} else {
|
||||
addToByKeys = false;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyLoadingImage != null && addToByKeys) {
|
||||
alreadyLoadingImage.addImageView(imageView);
|
||||
imageLoadingByKeys.put(TAG, alreadyLoadingImage);
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
CacheImage img = new CacheImage();
|
||||
img.key = filter;
|
||||
img.addImageView(imageView);
|
||||
imageLoadingByKeys.put(TAG, img);
|
||||
imageLoading.put(filter, img);
|
||||
|
||||
enqueueImageProcessingOperationWithImage(image, filter, filter, img);
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueImageProcessingOperationWithImage(final Bitmap image, final String filter, final String key, final CacheImage img) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Object v : img.imageViewArray) {
|
||||
imageLoadingByKeys.remove(getTag(v));
|
||||
}
|
||||
checkOperationsAndClear(img.loadOperation);
|
||||
imageLoading.remove(key);
|
||||
}
|
||||
});
|
||||
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
img.callAndClear(image);
|
||||
if (image != null && memCache.get(key) == null) {
|
||||
memCache.put(key, image);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight) {
|
||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||
bmOptions.inJustDecodeBounds = true;
|
||||
|
@ -49,13 +49,13 @@ public class GcmBroadcastReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
AwakeService.startService();
|
||||
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationLoader.postInitApplication();
|
||||
|
||||
AwakeService.startService();
|
||||
|
||||
try {
|
||||
String key = intent.getStringExtra("loc_key");
|
||||
if ("DC_UPDATE".equals(key)) {
|
||||
|
@ -12,9 +12,13 @@ import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.telegram.ui.ApplicationLoader;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
@ -26,6 +30,7 @@ import java.util.Locale;
|
||||
public class LocaleController {
|
||||
|
||||
public static boolean isRTL = false;
|
||||
private static boolean is24HourFormat = false;
|
||||
public static FastDateFormat formatterDay;
|
||||
public static FastDateFormat formatterWeek;
|
||||
public static FastDateFormat formatterMonth;
|
||||
@ -37,6 +42,7 @@ public class LocaleController {
|
||||
private Locale currentLocale;
|
||||
private Locale systemDefaultLocale;
|
||||
private LocaleInfo currentLocaleInfo;
|
||||
private LocaleInfo defaultLocalInfo;
|
||||
private HashMap<String, String> localeValues = new HashMap<String, String>();
|
||||
private String languageOverride;
|
||||
private boolean changingConfiguration = false;
|
||||
@ -45,11 +51,34 @@ public class LocaleController {
|
||||
public String name;
|
||||
public String nameEnglish;
|
||||
public String shortName;
|
||||
public String pathToFile;
|
||||
|
||||
public String getSaveString() {
|
||||
return name + "|" + nameEnglish + "|" + shortName + "|" + pathToFile;
|
||||
}
|
||||
|
||||
public static LocaleInfo createWithString(String string) {
|
||||
if (string == null || string.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
String[] args = string.split("\\|");
|
||||
if (args.length != 4) {
|
||||
return null;
|
||||
}
|
||||
LocaleInfo localeInfo = new LocaleInfo();
|
||||
localeInfo.name = args[0];
|
||||
localeInfo.nameEnglish = args[1];
|
||||
localeInfo.shortName = args[2];
|
||||
localeInfo.pathToFile = args[3];
|
||||
return localeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<LocaleInfo> sortedLanguages = new ArrayList<LocaleController.LocaleInfo>();
|
||||
public HashMap<String, LocaleInfo> languagesDict = new HashMap<String, LocaleInfo>();
|
||||
|
||||
private ArrayList<LocaleInfo> otherLanguages = new ArrayList<LocaleInfo>();
|
||||
|
||||
private static volatile LocaleController Instance = null;
|
||||
public static LocaleController getInstance() {
|
||||
LocaleController localInstance = Instance;
|
||||
@ -65,48 +94,60 @@ public class LocaleController {
|
||||
}
|
||||
|
||||
public LocaleController() {
|
||||
LocaleController.LocaleInfo localeInfo = new LocaleController.LocaleInfo();
|
||||
LocaleInfo localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "English";
|
||||
localeInfo.nameEnglish = "English";
|
||||
localeInfo.shortName = "en";
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "Italiano";
|
||||
localeInfo.nameEnglish = "Italian";
|
||||
localeInfo.shortName = "it";
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "Español";
|
||||
localeInfo.nameEnglish = "Spanish";
|
||||
localeInfo.shortName = "es";
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "Deutsch";
|
||||
localeInfo.nameEnglish = "German";
|
||||
localeInfo.shortName = "de";
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "Nederlands";
|
||||
localeInfo.nameEnglish = "Dutch";
|
||||
localeInfo.shortName = "nl";
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "العربية";
|
||||
localeInfo.nameEnglish = "Arabic";
|
||||
localeInfo.shortName = "ar";
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
loadOtherLanguages();
|
||||
|
||||
for (LocaleInfo locale : otherLanguages) {
|
||||
sortedLanguages.add(locale);
|
||||
languagesDict.put(locale.shortName, locale);
|
||||
}
|
||||
|
||||
Collections.sort(sortedLanguages, new Comparator<LocaleInfo>() {
|
||||
@Override
|
||||
public int compare(LocaleController.LocaleInfo o, LocaleController.LocaleInfo o2) {
|
||||
@ -114,13 +155,15 @@ public class LocaleController {
|
||||
}
|
||||
});
|
||||
|
||||
localeInfo = new LocaleController.LocaleInfo();
|
||||
defaultLocalInfo = localeInfo = new LocaleController.LocaleInfo();
|
||||
localeInfo.name = "System default";
|
||||
localeInfo.nameEnglish = "System default";
|
||||
localeInfo.shortName = null;
|
||||
localeInfo.pathToFile = null;
|
||||
sortedLanguages.add(0, localeInfo);
|
||||
|
||||
systemDefaultLocale = Locale.getDefault();
|
||||
is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext);
|
||||
LocaleInfo currentInfo = null;
|
||||
boolean override = false;
|
||||
|
||||
@ -146,7 +189,167 @@ public class LocaleController {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applyLanguageFile(File file) {
|
||||
try {
|
||||
HashMap<String, String> stringMap = getLocaleFileStrings(file);
|
||||
|
||||
String languageName = stringMap.get("LanguageName");
|
||||
String languageNameInEnglish = stringMap.get("LanguageNameInEnglish");
|
||||
String languageCode = stringMap.get("LanguageCode");
|
||||
|
||||
if (languageName != null && languageName.length() > 0 &&
|
||||
languageNameInEnglish != null && languageNameInEnglish.length() > 0 &&
|
||||
languageCode != null && languageCode.length() > 0) {
|
||||
|
||||
if (languageName.contains("&") || languageName.contains("|")) {
|
||||
return false;
|
||||
}
|
||||
if (languageNameInEnglish.contains("&") || languageNameInEnglish.contains("|")) {
|
||||
return false;
|
||||
}
|
||||
if (languageCode.contains("&") || languageCode.contains("|")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File finalFile = new File(ApplicationLoader.applicationContext.getFilesDir(), languageCode + ".xml");
|
||||
if (!Utilities.copyFile(file, finalFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LocaleInfo localeInfo = languagesDict.get(languageCode);
|
||||
if (localeInfo == null) {
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = languageName;
|
||||
localeInfo.nameEnglish = languageNameInEnglish;
|
||||
localeInfo.shortName = languageCode;
|
||||
|
||||
localeInfo.pathToFile = finalFile.getAbsolutePath();
|
||||
sortedLanguages.add(localeInfo);
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
otherLanguages.add(localeInfo);
|
||||
|
||||
Collections.sort(sortedLanguages, new Comparator<LocaleInfo>() {
|
||||
@Override
|
||||
public int compare(LocaleController.LocaleInfo o, LocaleController.LocaleInfo o2) {
|
||||
if (o.shortName == null) {
|
||||
return -1;
|
||||
} else if (o2.shortName == null) {
|
||||
return 1;
|
||||
}
|
||||
return o.name.compareTo(o2.name);
|
||||
}
|
||||
});
|
||||
saveOtherLanguages();
|
||||
}
|
||||
localeValues = stringMap;
|
||||
applyLanguage(localeInfo, true, true);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void saveOtherLanguages() {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("langconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
String locales = "";
|
||||
for (LocaleInfo localeInfo : otherLanguages) {
|
||||
String loc = localeInfo.getSaveString();
|
||||
if (loc != null) {
|
||||
if (locales.length() != 0) {
|
||||
locales += "&";
|
||||
}
|
||||
locales += loc;
|
||||
}
|
||||
}
|
||||
editor.putString("locales", locales);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public boolean deleteLanguage(LocaleInfo localeInfo) {
|
||||
if (localeInfo.pathToFile == null) {
|
||||
return false;
|
||||
}
|
||||
if (currentLocaleInfo == localeInfo) {
|
||||
applyLanguage(defaultLocalInfo, true);
|
||||
}
|
||||
|
||||
otherLanguages.remove(localeInfo);
|
||||
sortedLanguages.remove(localeInfo);
|
||||
languagesDict.remove(localeInfo.shortName);
|
||||
File file = new File(localeInfo.pathToFile);
|
||||
file.delete();
|
||||
saveOtherLanguages();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadOtherLanguages() {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("langconfig", Activity.MODE_PRIVATE);
|
||||
String locales = preferences.getString("locales", null);
|
||||
if (locales == null || locales.length() == 0) {
|
||||
return;
|
||||
}
|
||||
String[] localesArr = locales.split("&");
|
||||
for (String locale : localesArr) {
|
||||
LocaleInfo localeInfo = LocaleInfo.createWithString(locale);
|
||||
if (localeInfo != null) {
|
||||
otherLanguages.add(localeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<String, String> getLocaleFileStrings(File file) {
|
||||
try {
|
||||
HashMap<String, String> stringMap = new HashMap<String, String>();
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new FileInputStream(file), "UTF-8");
|
||||
int eventType = parser.getEventType();
|
||||
String name = null;
|
||||
String value = null;
|
||||
String attrName = null;
|
||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
if(eventType == XmlPullParser.START_TAG) {
|
||||
name = parser.getName();
|
||||
int c = parser.getAttributeCount();
|
||||
if (c > 0) {
|
||||
attrName = parser.getAttributeValue(0);
|
||||
}
|
||||
} else if(eventType == XmlPullParser.TEXT) {
|
||||
if (attrName != null) {
|
||||
value = parser.getText();
|
||||
if (value != null) {
|
||||
value = value.trim();
|
||||
value = value.replace("\\n", "\n");
|
||||
value = value.replace("\\", "");
|
||||
}
|
||||
}
|
||||
} else if (eventType == XmlPullParser.END_TAG) {
|
||||
value = null;
|
||||
attrName = null;
|
||||
name = null;
|
||||
}
|
||||
if (name != null && name.equals("string") && value != null && attrName != null && value.length() != 0 && attrName.length() != 0) {
|
||||
stringMap.put(attrName, value);
|
||||
name = null;
|
||||
value = null;
|
||||
attrName = null;
|
||||
}
|
||||
eventType = parser.next();
|
||||
}
|
||||
return stringMap;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void applyLanguage(LocaleInfo localeInfo, boolean override) {
|
||||
applyLanguage(localeInfo, override, false);
|
||||
}
|
||||
|
||||
public void applyLanguage(LocaleInfo localeInfo, boolean override, boolean fromFile) {
|
||||
if (localeInfo == null) {
|
||||
return;
|
||||
}
|
||||
@ -173,6 +376,11 @@ public class LocaleController {
|
||||
editor.commit();
|
||||
}
|
||||
if (newLocale != null) {
|
||||
if (localeInfo.pathToFile == null) {
|
||||
localeValues.clear();
|
||||
} else if (!fromFile) {
|
||||
localeValues = getLocaleFileStrings(new File(localeInfo.pathToFile));
|
||||
}
|
||||
currentLocale = newLocale;
|
||||
currentLocaleInfo = localeInfo;
|
||||
changingConfiguration = true;
|
||||
@ -194,7 +402,7 @@ public class LocaleController {
|
||||
}
|
||||
|
||||
public static String getCurrentLanguageName() {
|
||||
return getString("LanguangeName", R.string.LanguangeName);
|
||||
return getString("LanguageName", R.string.LanguageName);
|
||||
}
|
||||
|
||||
public static String getString(String key, int res) {
|
||||
@ -226,6 +434,7 @@ public class LocaleController {
|
||||
if (changingConfiguration) {
|
||||
return;
|
||||
}
|
||||
is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext);
|
||||
systemDefaultLocale = newConfig.locale;
|
||||
if (languageOverride != null) {
|
||||
LocaleInfo toSet = currentLocaleInfo;
|
||||
@ -324,7 +533,7 @@ public class LocaleController {
|
||||
formatterWeek = FastDateFormat.getInstance("EEE", locale);
|
||||
|
||||
if (lang != null) {
|
||||
if (DateFormat.is24HourFormat(ApplicationLoader.applicationContext)) {
|
||||
if (is24HourFormat) {
|
||||
formatterDay = FastDateFormat.getInstance("HH:mm", locale);
|
||||
} else {
|
||||
if (lang.toLowerCase().equals("ar")) {
|
||||
|
@ -20,9 +20,12 @@ import android.media.audiofx.AutomaticGainControl;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.Vibrator;
|
||||
import android.view.View;
|
||||
|
||||
import org.telegram.objects.MessageObject;
|
||||
import org.telegram.ui.ApplicationLoader;
|
||||
import org.telegram.ui.Cells.ChatMediaCell;
|
||||
import org.telegram.ui.Views.GifDrawable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -45,17 +48,16 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
private native int seekOpusFile(float position);
|
||||
private native int isOpusFile(String path);
|
||||
private native void closeOpusFile();
|
||||
private native void readOpusFile(ByteBuffer buffer, int capacity);
|
||||
private native int getFinished();
|
||||
private native int getSize();
|
||||
private native long getPcmOffset();
|
||||
private native void readOpusFile(ByteBuffer buffer, int capacity, int[] args);
|
||||
private native long getTotalPcmDuration();
|
||||
|
||||
public static int[] readArgs = new int[3];
|
||||
|
||||
public static interface FileDownloadProgressListener {
|
||||
public void onFailedDownload(String fileName);
|
||||
public void onSuccessDownload(String fileName);
|
||||
public void onProgressDownload(String fileName, float progress);
|
||||
public void onProgressUpload(String fileName, float progress, boolean isEncrypted);
|
||||
public int getObserverTag();
|
||||
}
|
||||
|
||||
@ -86,6 +88,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
private ArrayList<FileDownloadProgressListener> deleteLaterArray = new ArrayList<FileDownloadProgressListener>();
|
||||
private int lastTag = 0;
|
||||
|
||||
private GifDrawable currentGifDrawable;
|
||||
private MessageObject currentGifMessageObject;
|
||||
private ChatMediaCell currentMediaCell;
|
||||
|
||||
private boolean isPaused = false;
|
||||
private MediaPlayer audioPlayer = null;
|
||||
private AudioTrack audioTrackPlayer = null;
|
||||
@ -228,6 +234,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileDidFailedLoad);
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileDidLoaded);
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileLoadProgressChanged);
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileUploadProgressChanged);
|
||||
|
||||
Timer progressTimer = new Timer();
|
||||
progressTimer.schedule(new TimerTask() {
|
||||
@ -275,6 +282,12 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
|
||||
public void cleanup() {
|
||||
clenupPlayer(false);
|
||||
if (currentGifDrawable != null) {
|
||||
currentGifDrawable.recycle();
|
||||
currentGifDrawable = null;
|
||||
}
|
||||
currentMediaCell = null;
|
||||
currentGifMessageObject = null;
|
||||
}
|
||||
|
||||
public int generateObserverTag() {
|
||||
@ -379,6 +392,22 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
}
|
||||
listenerInProgress = false;
|
||||
processLaterArrays();
|
||||
} else if (id == FileLoader.FileUploadProgressChanged) {
|
||||
String location = (String)args[0];
|
||||
listenerInProgress = true;
|
||||
String fileName = (String)args[0];
|
||||
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
|
||||
if (arrayList != null) {
|
||||
Float progress = (Float)args[1];
|
||||
Boolean enc = (Boolean)args[2];
|
||||
for (WeakReference<FileDownloadProgressListener> reference : arrayList) {
|
||||
if (reference.get() != null) {
|
||||
reference.get().onProgressUpload(fileName, progress, enc);
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerInProgress = false;
|
||||
processLaterArrays();
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,10 +432,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
}
|
||||
}
|
||||
if (buffer != null) {
|
||||
readOpusFile(buffer.buffer, playerBufferSize);
|
||||
buffer.size = getSize();
|
||||
buffer.pcmOffset = getPcmOffset();
|
||||
buffer.finished = getFinished();
|
||||
readOpusFile(buffer.buffer, playerBufferSize, readArgs);
|
||||
buffer.size = readArgs[0];
|
||||
buffer.pcmOffset = readArgs[1];
|
||||
buffer.finished = readArgs[2];
|
||||
if (buffer.finished == 1) {
|
||||
decodingFinished = true;
|
||||
}
|
||||
@ -832,6 +861,9 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
fileBuffer.rewind();
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 16) {
|
||||
File f = new File("/vendor/lib/libaudioeffect_jni.so");
|
||||
File f2 = new File("/system/lib/libaudioeffect_jni.so");
|
||||
if (f.exists() || f2.exists()) {
|
||||
AutomaticGainControl agc = null;
|
||||
try {
|
||||
if (AutomaticGainControl.isAvailable()) {
|
||||
@ -851,6 +883,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audioRecorder.startRecording();
|
||||
} catch (Exception e) {
|
||||
@ -1077,4 +1110,73 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public GifDrawable getGifDrawable(ChatMediaCell cell, boolean create) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MessageObject messageObject = cell.getMessageObject();
|
||||
if (messageObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (currentGifMessageObject != null && messageObject.messageOwner.id == currentGifMessageObject.messageOwner.id) {
|
||||
currentMediaCell = cell;
|
||||
currentGifDrawable.parentView = new WeakReference<View>(cell);
|
||||
return currentGifDrawable;
|
||||
}
|
||||
|
||||
if (create) {
|
||||
if (currentMediaCell != null) {
|
||||
if (currentGifDrawable != null) {
|
||||
currentGifDrawable.stop();
|
||||
currentGifDrawable.recycle();
|
||||
}
|
||||
currentMediaCell.clearGifImage();
|
||||
}
|
||||
currentGifMessageObject = cell.getMessageObject();
|
||||
currentMediaCell = cell;
|
||||
|
||||
File cacheFile = null;
|
||||
if (currentGifMessageObject.messageOwner.attachPath != null && currentGifMessageObject.messageOwner.attachPath.length() != 0) {
|
||||
File f = new File(currentGifMessageObject.messageOwner.attachPath);
|
||||
if (f.length() > 0) {
|
||||
cacheFile = f;
|
||||
}
|
||||
} else {
|
||||
cacheFile = new File(Utilities.getCacheDir(), messageObject.getFileName());
|
||||
}
|
||||
try {
|
||||
currentGifDrawable = new GifDrawable(cacheFile);
|
||||
currentGifDrawable.parentView = new WeakReference<View>(cell);
|
||||
return currentGifDrawable;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearGifDrawable(ChatMediaCell cell) {
|
||||
if (cell == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageObject messageObject = cell.getMessageObject();
|
||||
if (messageObject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentGifMessageObject != null && messageObject.messageOwner.id == currentGifMessageObject.messageOwner.id) {
|
||||
if (currentGifDrawable != null) {
|
||||
currentGifDrawable.stop();
|
||||
currentGifDrawable.recycle();
|
||||
currentGifDrawable = null;
|
||||
}
|
||||
currentMediaCell = null;
|
||||
currentGifMessageObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import android.media.AudioManager;
|
||||
import android.media.SoundPool;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
@ -100,7 +99,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
public int fontSize = Utilities.dp(16);
|
||||
public long scheduleContactsReload = 0;
|
||||
|
||||
public static volatile boolean isScreenOn = true;
|
||||
public MessageObject currentPushMessage;
|
||||
|
||||
private class UserActionUpdates extends TLRPC.Updates {
|
||||
@ -201,14 +199,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
}
|
||||
|
||||
public MessagesController() {
|
||||
try {
|
||||
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
||||
isScreenOn = pm.isScreenOn();
|
||||
FileLog.e("tmessages", "screen state = " + isScreenOn);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
|
||||
MessagesStorage storage = MessagesStorage.getInstance();
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileDidUpload);
|
||||
NotificationCenter.getInstance().addObserver(this, FileLoader.FileDidFailUpload);
|
||||
@ -1895,6 +1885,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
delayedMessage.type = 2;
|
||||
delayedMessage.obj = newMsgObj;
|
||||
delayedMessage.documentLocation = document;
|
||||
delayedMessage.location = document.thumb.location;
|
||||
performSendDelayedMessage(delayedMessage);
|
||||
} else if (type == 8) {
|
||||
reqSend.media = new TLRPC.TL_inputMediaUploadedAudio();
|
||||
@ -1976,9 +1967,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
random.nextBytes(reqSend.media.iv);
|
||||
random.nextBytes(reqSend.media.key);
|
||||
reqSend.media.size = document.size;
|
||||
if (!(document.thumb instanceof TLRPC.TL_photoSizeEmpty)) {
|
||||
reqSend.media.thumb = document.thumb.bytes;
|
||||
reqSend.media.thumb_h = document.thumb.h;
|
||||
reqSend.media.thumb_w = document.thumb.w;
|
||||
} else {
|
||||
reqSend.media.thumb = new byte[0];
|
||||
reqSend.media.thumb_h = 0;
|
||||
reqSend.media.thumb_w = 0;
|
||||
}
|
||||
reqSend.media.file_name = document.file_name;
|
||||
reqSend.media.mime_type = document.mime_type;
|
||||
|
||||
@ -2051,18 +2048,30 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
if (size2.location != null && size.location != null && !(size instanceof TLRPC.TL_photoSizeEmpty) && !(size2 instanceof TLRPC.TL_photoSizeEmpty)) {
|
||||
String fileName = size2.location.volume_id + "_" + size2.location.local_id;
|
||||
String fileName2 = size.location.volume_id + "_" + size.location.local_id;
|
||||
if (fileName.equals(fileName2)) {
|
||||
return;
|
||||
}
|
||||
if (!fileName.equals(fileName2)) {
|
||||
File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg");
|
||||
File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg");
|
||||
boolean result = cacheFile.renameTo(cacheFile2);
|
||||
FileLoader.getInstance().replaceImageInCache(fileName, fileName2);
|
||||
size2.location = size.location;
|
||||
}
|
||||
}
|
||||
sentMessage.message = newMsg.message;
|
||||
sentMessage.attachPath = newMsg.attachPath;
|
||||
}
|
||||
} else if (sentMessage.media instanceof TLRPC.TL_messageMediaDocument && sentMessage.media.document != null && newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) {
|
||||
TLRPC.PhotoSize size2 = newMsg.media.document.thumb;
|
||||
TLRPC.PhotoSize size = sentMessage.media.document.thumb;
|
||||
if (size2.location != null && size.location != null && !(size instanceof TLRPC.TL_photoSizeEmpty) && !(size2 instanceof TLRPC.TL_photoSizeEmpty)) {
|
||||
String fileName = size2.location.volume_id + "_" + size2.location.local_id;
|
||||
String fileName2 = size.location.volume_id + "_" + size.location.local_id;
|
||||
if (!fileName.equals(fileName2)) {
|
||||
File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg");
|
||||
File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg");
|
||||
boolean result = cacheFile.renameTo(cacheFile2);
|
||||
FileLoader.getInstance().replaceImageInCache(fileName, fileName2);
|
||||
size2.location = size.location;
|
||||
}
|
||||
}
|
||||
sentMessage.message = newMsg.message;
|
||||
sentMessage.attachPath = newMsg.attachPath;
|
||||
} else if (sentMessage.media instanceof TLRPC.TL_messageMediaAudio && sentMessage.media.audio != null && newMsg.media instanceof TLRPC.TL_messageMediaAudio && newMsg.media.audio != null) {
|
||||
@ -2071,15 +2080,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
|
||||
String fileName = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".m4a";
|
||||
String fileName2 = sentMessage.media.audio.dc_id + "_" + sentMessage.media.audio.id + ".m4a";
|
||||
if (fileName.equals(fileName2)) {
|
||||
return;
|
||||
}
|
||||
if (!fileName.equals(fileName2)) {
|
||||
File cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
File cacheFile2 = new File(Utilities.getCacheDir(), fileName2);
|
||||
cacheFile.renameTo(cacheFile2);
|
||||
newMsg.media.audio.dc_id = sentMessage.media.audio.dc_id;
|
||||
newMsg.media.audio.id = sentMessage.media.audio.id;
|
||||
}
|
||||
}
|
||||
} else if (file != null) {
|
||||
if (newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) {
|
||||
TLRPC.PhotoSize size = newMsg.media.photo.sizes.get(newMsg.media.photo.sizes.size() - 1);
|
||||
@ -2154,12 +2162,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
|
||||
String fileName = audio.dc_id + "_" + audio.id + ".m4a";
|
||||
String fileName2 = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".m4a";
|
||||
if (fileName.equals(fileName2)) {
|
||||
return;
|
||||
}
|
||||
if (!fileName.equals(fileName2)) {
|
||||
File cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
File cacheFile2 = new File(Utilities.getCacheDir(), fileName2);
|
||||
cacheFile.renameTo(cacheFile2);
|
||||
}
|
||||
|
||||
ArrayList<TLRPC.Message> arr = new ArrayList<TLRPC.Message>();
|
||||
arr.add(newMsg);
|
||||
@ -2169,7 +2176,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
}
|
||||
|
||||
private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final MessageObject newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile) {
|
||||
if (req == null) {
|
||||
if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) {
|
||||
return;
|
||||
}
|
||||
//TLRPC.decryptedMessageLayer messageLayer = new TLRPC.decryptedMessageLayer();
|
||||
@ -2429,6 +2436,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
FileLoader.getInstance().uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
|
||||
}
|
||||
} else if (message.type == 2) {
|
||||
if (message.sendRequest != null && message.sendRequest.media.thumb == null && message.location != null) {
|
||||
String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg";
|
||||
putToDelayedMessages(location, message);
|
||||
FileLoader.getInstance().uploadFile(location, null, null);
|
||||
} else {
|
||||
String location = message.documentLocation.path;
|
||||
putToDelayedMessages(location, message);
|
||||
if (message.sendRequest != null) {
|
||||
@ -2436,6 +2448,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
} else {
|
||||
FileLoader.getInstance().uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
|
||||
}
|
||||
}
|
||||
} else if (message.type == 3) {
|
||||
String location = message.audioLocation.path;
|
||||
putToDelayedMessages(location, message);
|
||||
@ -2545,8 +2558,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
performSendMessageRequest(message.sendRequest, message.obj);
|
||||
}
|
||||
} else if (message.type == 2) {
|
||||
if (message.sendRequest.media.thumb == null && message.location != null) {
|
||||
message.sendRequest.media.thumb = file;
|
||||
performSendDelayedMessage(message);
|
||||
} else {
|
||||
message.sendRequest.media.file = file;
|
||||
performSendMessageRequest(message.sendRequest, message.obj);
|
||||
}
|
||||
} else if (message.type == 3) {
|
||||
message.sendRequest.media.file = file;
|
||||
performSendMessageRequest(message.sendRequest, message.obj);
|
||||
@ -3345,7 +3363,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
});
|
||||
} else {
|
||||
gettingDifference = false;
|
||||
loadCurrentState();
|
||||
getDifference();
|
||||
FileLog.e("tmessages", "get difference error, don't know what to do :(");
|
||||
}
|
||||
}
|
||||
@ -3396,7 +3414,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
} else {
|
||||
dialog_id = obj.messageOwner.to_id.user_id;
|
||||
}
|
||||
if (dialog_id != openned_dialog_id || ApplicationLoader.lastPauseTime != 0 || !isScreenOn) {
|
||||
if (dialog_id != openned_dialog_id || ApplicationLoader.lastPauseTime != 0 || !ApplicationLoader.isScreenOn) {
|
||||
showInAppNotification(obj);
|
||||
}
|
||||
}
|
||||
@ -3455,7 +3473,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
} else {
|
||||
dialog_id = obj.messageOwner.to_id.user_id;
|
||||
}
|
||||
if (dialog_id != openned_dialog_id || ApplicationLoader.lastPauseTime != 0 || !isScreenOn) {
|
||||
if (dialog_id != openned_dialog_id || ApplicationLoader.lastPauseTime != 0 || !ApplicationLoader.isScreenOn) {
|
||||
showInAppNotification(obj);
|
||||
}
|
||||
}
|
||||
@ -4212,7 +4230,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApplicationLoader.lastPauseTime == 0 && isScreenOn) {
|
||||
if (ApplicationLoader.lastPauseTime == 0 && ApplicationLoader.isScreenOn) {
|
||||
boolean inAppSounds = preferences.getBoolean("EnableInAppSounds", true);
|
||||
boolean inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true);
|
||||
boolean inAppPreview = preferences.getBoolean("EnableInAppPreview", true);
|
||||
@ -4692,7 +4710,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
newMessage.media.geo.lat = decryptedMessage.media.lat;
|
||||
newMessage.media.geo._long = decryptedMessage.media._long;
|
||||
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaPhoto) {
|
||||
if (decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv.length != 32) {
|
||||
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
|
||||
return null;
|
||||
}
|
||||
newMessage.media = new TLRPC.TL_messageMediaPhoto();
|
||||
@ -4725,7 +4743,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
big.location.local_id = message.file.key_fingerprint;
|
||||
newMessage.media.photo.sizes.add(big);
|
||||
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVideo) {
|
||||
if (decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv.length != 32) {
|
||||
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
|
||||
return null;
|
||||
}
|
||||
newMessage.media = new TLRPC.TL_messageMediaVideo();
|
||||
@ -4754,7 +4772,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
newMessage.media.video.key = decryptedMessage.media.key;
|
||||
newMessage.media.video.iv = decryptedMessage.media.iv;
|
||||
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) {
|
||||
if (decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv.length != 32) {
|
||||
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
|
||||
return null;
|
||||
}
|
||||
newMessage.media = new TLRPC.TL_messageMediaDocument();
|
||||
@ -4781,7 +4799,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
}
|
||||
newMessage.media.document.dc_id = message.file.dc_id;
|
||||
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaAudio) {
|
||||
if (decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv.length != 32) {
|
||||
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
|
||||
return null;
|
||||
}
|
||||
newMessage.media = new TLRPC.TL_messageMediaAudio();
|
||||
|
@ -2825,4 +2825,109 @@ public class MessagesStorage {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public TLRPC.User getUser(final int user_id) {
|
||||
TLRPC.User user = null;
|
||||
try {
|
||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid = %d", user_id));
|
||||
if (cursor.next()) {
|
||||
byte[] userData = cursor.byteArrayValue(0);
|
||||
if (userData != null) {
|
||||
SerializedData data = new SerializedData(userData);
|
||||
user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||
if (user != null) {
|
||||
if (user.status != null) {
|
||||
user.status.expires = cursor.intValue(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.dispose();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public ArrayList<TLRPC.User> getUsers(final ArrayList<Integer> uids, final boolean[] error) {
|
||||
ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
|
||||
try {
|
||||
String uidsStr = "";
|
||||
|
||||
for (Integer uid : uids) {
|
||||
if (uidsStr.length() != 0) {
|
||||
uidsStr += ",";
|
||||
}
|
||||
uidsStr += uid;
|
||||
}
|
||||
|
||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN (%s)", uidsStr));
|
||||
while (cursor.next()) {
|
||||
byte[] userData = cursor.byteArrayValue(0);
|
||||
if (userData != null) {
|
||||
SerializedData data = new SerializedData(userData);
|
||||
TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||
if (user != null) {
|
||||
if (user.status != null) {
|
||||
user.status.expires = cursor.intValue(1);
|
||||
}
|
||||
users.add(user);
|
||||
} else {
|
||||
error[0] = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error[0] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cursor.dispose();
|
||||
} catch (Exception e) {
|
||||
error[0] = true;
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
public TLRPC.Chat getChat(final int chat_id) {
|
||||
TLRPC.Chat chat = null;
|
||||
try {
|
||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid = %d", chat_id));
|
||||
if (cursor.next()) {
|
||||
byte[] chatData = cursor.byteArrayValue(0);
|
||||
if (chatData != null) {
|
||||
SerializedData data = new SerializedData(chatData);
|
||||
chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||
}
|
||||
}
|
||||
cursor.dispose();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return chat;
|
||||
}
|
||||
|
||||
public TLRPC.EncryptedChat getEncryptedChat(final int chat_id) {
|
||||
TLRPC.EncryptedChat chat = null;
|
||||
try {
|
||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid = %d", chat_id));
|
||||
if (cursor.next()) {
|
||||
byte[] chatData = cursor.byteArrayValue(0);
|
||||
if (chatData != null) {
|
||||
SerializedData data = new SerializedData(chatData);
|
||||
chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||
if (chat != null) {
|
||||
chat.user_id = cursor.intValue(1);
|
||||
chat.a_or_b = cursor.byteArrayValue(2);
|
||||
chat.auth_key = cursor.byteArrayValue(3);
|
||||
chat.ttl = cursor.intValue(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.dispose();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
return chat;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ package org.telegram.messenger;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -22,9 +21,9 @@ import java.util.zip.ZipFile;
|
||||
public class NativeLoader {
|
||||
|
||||
private static final long sizes[] = new long[] {
|
||||
782992, //armeabi
|
||||
766628, //armeabi-v7a
|
||||
1352692, //x86
|
||||
795280, //armeabi
|
||||
778916, //armeabi-v7a
|
||||
1377300, //x86
|
||||
0, //mips
|
||||
};
|
||||
|
||||
@ -35,7 +34,7 @@ public class NativeLoader {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
if (Build.VERSION.SDK_INT > 10) {
|
||||
try {
|
||||
String folder = null;
|
||||
long libSize = 0;
|
||||
@ -48,6 +47,7 @@ public class NativeLoader {
|
||||
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
|
||||
folder = "armeabi";
|
||||
libSize = sizes[0];
|
||||
libSize2 = sizes[1];
|
||||
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
|
||||
folder = "x86";
|
||||
libSize = sizes[2];
|
||||
@ -57,13 +57,13 @@ public class NativeLoader {
|
||||
} else {
|
||||
System.loadLibrary("tmessages");
|
||||
nativeLoaded = true;
|
||||
Log.e("tmessages", "Unsupported arch: " + Build.CPU_ABI);
|
||||
FileLog.e("tmessages", "Unsupported arch: " + Build.CPU_ABI);
|
||||
return;
|
||||
}
|
||||
|
||||
File destFile = new File(context.getApplicationInfo().nativeLibraryDir + "/libtmessages.so");
|
||||
if (destFile.exists() && (destFile.length() == libSize || libSize2 != 0 && destFile.length() == libSize2)) {
|
||||
Log.d("tmessages", "Load normal lib");
|
||||
FileLog.d("tmessages", "Load normal lib");
|
||||
try {
|
||||
System.loadLibrary("tmessages");
|
||||
nativeLoaded = true;
|
||||
@ -77,7 +77,7 @@ public class NativeLoader {
|
||||
if (destLocalFile.exists()) {
|
||||
if (destLocalFile.length() == libSize) {
|
||||
try {
|
||||
Log.d("tmessages", "Load local lib");
|
||||
FileLog.d("tmessages", "Load local lib");
|
||||
System.load(destLocalFile.getAbsolutePath());
|
||||
nativeLoaded = true;
|
||||
return;
|
||||
@ -89,7 +89,7 @@ public class NativeLoader {
|
||||
}
|
||||
}
|
||||
|
||||
Log.e("tmessages", "Library not found, arch = " + folder);
|
||||
FileLog.e("tmessages", "Library not found, arch = " + folder);
|
||||
|
||||
ZipFile zipFile = null;
|
||||
InputStream stream = null;
|
||||
@ -114,25 +114,25 @@ public class NativeLoader {
|
||||
nativeLoaded = true;
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
FileLog.e("tmessages", e);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
if (zipFile != null) {
|
||||
try {
|
||||
zipFile.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,15 +12,17 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import org.telegram.ui.ApplicationLoader;
|
||||
|
||||
public class ScreenReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
FileLog.e("tmessages", "screen off");
|
||||
MessagesController.isScreenOn = false;
|
||||
ApplicationLoader.isScreenOn = false;
|
||||
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
|
||||
FileLog.e("tmessages", "screen on");
|
||||
MessagesController.isScreenOn = true;
|
||||
ApplicationLoader.isScreenOn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +76,6 @@ public class Utilities {
|
||||
|
||||
public static volatile DispatchQueue stageQueue = new DispatchQueue("stageQueue");
|
||||
public static volatile DispatchQueue globalQueue = new DispatchQueue("globalQueue");
|
||||
public static volatile DispatchQueue cacheOutQueue = new DispatchQueue("cacheOutQueue");
|
||||
public static volatile DispatchQueue imageLoadQueue = new DispatchQueue("imageLoadQueue");
|
||||
public static volatile DispatchQueue fileUploadQueue = new DispatchQueue("fileUploadQueue");
|
||||
|
||||
public static int[] arrColors = {0xffee4928, 0xff41a903, 0xffe09602, 0xff0f94ed, 0xff8f3bf7, 0xfffc4380, 0xff00a1c4, 0xffeb7002};
|
||||
public static int[] arrUsersAvatars = {
|
||||
|
@ -35,6 +35,7 @@ public class MessageObject {
|
||||
public TLRPC.Message messageOwner;
|
||||
public CharSequence messageText;
|
||||
public int type;
|
||||
public int contentType;
|
||||
public ArrayList<PhotoObject> photoThumbs;
|
||||
public Bitmap imagePreview;
|
||||
public PhotoObject previewPhoto;
|
||||
@ -244,6 +245,11 @@ public class MessageObject {
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) {
|
||||
messageText = LocaleController.getString("UnsuppotedMedia", R.string.UnsuppotedMedia);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||
if (!(message.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) {
|
||||
photoThumbs = new ArrayList<PhotoObject>();
|
||||
PhotoObject obj = new PhotoObject(message.media.document.thumb);
|
||||
photoThumbs.add(obj);
|
||||
}
|
||||
messageText = LocaleController.getString("AttachDocument", R.string.AttachDocument);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaAudio) {
|
||||
messageText = LocaleController.getString("AttachAudio", R.string.AttachAudio);
|
||||
@ -255,68 +261,53 @@ public class MessageObject {
|
||||
|
||||
if (message instanceof TLRPC.TL_message || (message instanceof TLRPC.TL_messageForwarded && (message.media == null || !(message.media instanceof TLRPC.TL_messageMediaEmpty)))) {
|
||||
if (message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 0;
|
||||
} else {
|
||||
type = 1;
|
||||
}
|
||||
contentType = type = 0;
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 2;
|
||||
} else {
|
||||
type = 3;
|
||||
}
|
||||
contentType = type = 1;
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaGeo) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 4;
|
||||
contentType = type = 4;
|
||||
} else {
|
||||
type = 5;
|
||||
contentType = type = 5;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaVideo) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 6;
|
||||
contentType = type = 6;
|
||||
} else {
|
||||
type = 7;
|
||||
contentType = type = 7;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaContact) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 12;
|
||||
contentType = type = 12;
|
||||
} else {
|
||||
type = 13;
|
||||
contentType = type = 13;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaUnsupported) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 0;
|
||||
} else {
|
||||
type = 1;
|
||||
}
|
||||
contentType = type = 0;
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaDocument) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 16;
|
||||
if (message.media.document.thumb != null && !(message.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty) && message.media.document.mime_type != null && message.media.document.mime_type.equals("image/gif")) {
|
||||
contentType = 1;
|
||||
type = 8;
|
||||
} else {
|
||||
type = 17;
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
contentType = type = 8;
|
||||
} else {
|
||||
contentType = type = 9;
|
||||
}
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaAudio) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 18;
|
||||
} else {
|
||||
type = 19;
|
||||
}
|
||||
contentType = type = 2;
|
||||
}
|
||||
} else if (message instanceof TLRPC.TL_messageService) {
|
||||
if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
|
||||
type = 1;
|
||||
contentType = type = 0;
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
|
||||
type = 11;
|
||||
contentType = type = 11;
|
||||
} else {
|
||||
type = 10;
|
||||
contentType = type = 10;
|
||||
}
|
||||
} else if (message instanceof TLRPC.TL_messageForwarded) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 8;
|
||||
} else {
|
||||
type = 9;
|
||||
}
|
||||
contentType = type = 0;
|
||||
}
|
||||
|
||||
Calendar rightNow = new GregorianCalendar();
|
||||
|
@ -60,6 +60,9 @@ public class PhotoObject {
|
||||
int closestHeight = 9999;
|
||||
TLRPC.PhotoSize closestObject = null;
|
||||
for (TLRPC.PhotoSize obj : sizes) {
|
||||
if (obj == null) {
|
||||
continue;
|
||||
}
|
||||
int diffW = Math.abs(obj.w - width);
|
||||
int diffH = Math.abs(obj.h - height);
|
||||
if (closestObject == null || closestObject instanceof TLRPC.TL_photoCachedSize || closestWidth > diffW || closestHeight > diffH) {
|
||||
|
@ -21,6 +21,7 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
@ -56,6 +57,7 @@ public class ApplicationLoader extends Application {
|
||||
public static volatile Context applicationContext = null;
|
||||
public static volatile Handler applicationHandler = null;
|
||||
private static volatile boolean applicationInited = false;
|
||||
public static volatile boolean isScreenOn = false;
|
||||
|
||||
public static ArrayList<BaseFragment> fragmentsStack = new ArrayList<BaseFragment>();
|
||||
|
||||
@ -63,10 +65,17 @@ public class ApplicationLoader extends Application {
|
||||
if (applicationInited) {
|
||||
return;
|
||||
}
|
||||
|
||||
applicationInited = true;
|
||||
|
||||
NativeLoader.initNativeLibs(applicationContext);
|
||||
|
||||
try {
|
||||
LocaleController.getInstance();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
@ -76,6 +85,14 @@ public class ApplicationLoader extends Application {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
||||
isScreenOn = pm.isScreenOn();
|
||||
FileLog.e("tmessages", "screen state = " + isScreenOn);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
|
||||
UserConfig.loadConfig();
|
||||
if (UserConfig.currentUser != null) {
|
||||
boolean changed = false;
|
||||
@ -119,12 +136,6 @@ public class ApplicationLoader extends Application {
|
||||
super.onCreate();
|
||||
lastPauseTime = System.currentTimeMillis();
|
||||
applicationContext = getApplicationContext();
|
||||
NativeLoader.initNativeLibs(this);
|
||||
try {
|
||||
LocaleController.getInstance();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
applicationHandler = new Handler(applicationContext.getMainLooper());
|
||||
|
||||
|
@ -60,8 +60,8 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
private TLRPC.FileLocation currentPhoto;
|
||||
private String currentNameString;
|
||||
|
||||
public ChatAudioCell(Context context, boolean isChat) {
|
||||
super(context, isChat);
|
||||
public ChatAudioCell(Context context) {
|
||||
super(context, false);
|
||||
TAG = MediaController.getInstance().generateObserverTag();
|
||||
|
||||
avatarImage = new ImageReceiver();
|
||||
@ -94,6 +94,16 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (avatarImage != null) {
|
||||
avatarImage.clearImage();
|
||||
currentPhoto = null;
|
||||
}
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
float x = event.getX();
|
||||
@ -221,7 +231,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
}
|
||||
progressView.setProgress(0);
|
||||
} else {
|
||||
MediaController.getInstance().addLoadingFileObserver(currentMessageObject.getFileName(), this);
|
||||
MediaController.getInstance().addLoadingFileObserver(fileName, this);
|
||||
if (!FileLoader.getInstance().isLoadingFile(fileName)) {
|
||||
buttonState = 2;
|
||||
progressView.setProgress(0);
|
||||
@ -254,6 +264,11 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressUpload(String fileName, float progress, boolean isEncrypted) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObserverTag() {
|
||||
return TAG;
|
||||
@ -272,7 +287,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
setMeasuredDimension(width, Utilities.dp(68));
|
||||
if (chat) {
|
||||
if (isChat) {
|
||||
backgroundWidth = Math.min(width - Utilities.dp(102), Utilities.dp(300));
|
||||
} else {
|
||||
backgroundWidth = Math.min(width - Utilities.dp(50), Utilities.dp(300));
|
||||
@ -289,7 +304,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
buttonX = layoutWidth - backgroundWidth + Utilities.dp(67);
|
||||
timeX = layoutWidth - backgroundWidth + Utilities.dp(71);
|
||||
} else {
|
||||
if (chat) {
|
||||
if (isChat) {
|
||||
avatarImage.imageX = Utilities.dp(69);
|
||||
seekBarX = Utilities.dp(158);
|
||||
buttonX = Utilities.dp(128);
|
||||
@ -346,10 +361,10 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
|
||||
if (messageObject.messageOwner.out) {
|
||||
seekBar.type = 0;
|
||||
progressView.type = 0;
|
||||
progressView.setProgressColors(0xffb4e396, 0xff6ac453);
|
||||
} else {
|
||||
seekBar.type = 1;
|
||||
progressView.type = 1;
|
||||
progressView.setProgressColors(0xffd9e2eb, 0xff86c5f8);
|
||||
}
|
||||
|
||||
super.setMessageObject(messageObject);
|
||||
@ -396,10 +411,4 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega
|
||||
timeLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,11 @@ import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SoundEffectConstants;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
@ -28,6 +30,7 @@ import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.objects.MessageObject;
|
||||
import org.telegram.ui.Views.ImageReceiver;
|
||||
import org.telegram.ui.Views.OnSwipeTouchListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@ -35,25 +38,41 @@ public class ChatBaseCell extends BaseCell {
|
||||
|
||||
public static interface ChatBaseCellDelegate {
|
||||
public abstract void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user);
|
||||
public abstract void didPressedCanceSendButton(ChatBaseCell cell);
|
||||
public abstract void didLongPressed(ChatBaseCell cell);
|
||||
public abstract boolean canPerformActions();
|
||||
public boolean onSwipeLeft();
|
||||
public boolean onSwipeRight();
|
||||
}
|
||||
|
||||
protected boolean chat;
|
||||
public boolean isChat = false;
|
||||
protected boolean isPressed = false;
|
||||
protected boolean forwardName = false;
|
||||
protected boolean media = false;
|
||||
private boolean isCheckPressed = true;
|
||||
private boolean wasLayout = false;
|
||||
protected boolean isAvatarVisible = false;
|
||||
protected MessageObject currentMessageObject;
|
||||
|
||||
private static Drawable backgroundDrawableIn;
|
||||
private static Drawable backgroundDrawableInSelected;
|
||||
private static Drawable backgroundDrawableOut;
|
||||
private static Drawable backgroundDrawableOutSelected;
|
||||
private static Drawable backgroundMediaDrawableIn;
|
||||
private static Drawable backgroundMediaDrawableInSelected;
|
||||
private static Drawable backgroundMediaDrawableOut;
|
||||
private static Drawable backgroundMediaDrawableOutSelected;
|
||||
private static Drawable checkDrawable;
|
||||
private static Drawable halfCheckDrawable;
|
||||
private static Drawable clockDrawable;
|
||||
private static Drawable checkMediaDrawable;
|
||||
private static Drawable halfCheckMediaDrawable;
|
||||
private static Drawable clockMediaDrawable;
|
||||
private static Drawable errorDrawable;
|
||||
protected static Drawable mediaBackgroundDrawable;
|
||||
private static TextPaint timePaintIn;
|
||||
private static TextPaint timePaintOut;
|
||||
private static TextPaint timeMediaPaint;
|
||||
private static TextPaint namePaint;
|
||||
private static TextPaint forwardNamePaint;
|
||||
|
||||
@ -95,26 +114,89 @@ public class ChatBaseCell extends BaseCell {
|
||||
|
||||
protected int namesOffset = 0;
|
||||
|
||||
public ChatBaseCell(Context context, boolean isChat) {
|
||||
private boolean checkingForLongPress = false;
|
||||
private int pressCount = 0;
|
||||
private CheckForLongPress pendingCheckForLongPress = null;
|
||||
private CheckForTap pendingCheckForTap = null;
|
||||
private OnSwipeTouchListener onSwipeTouchListener;
|
||||
|
||||
private final class CheckForTap implements Runnable {
|
||||
public void run() {
|
||||
if (pendingCheckForLongPress == null) {
|
||||
pendingCheckForLongPress = new CheckForLongPress();
|
||||
}
|
||||
pendingCheckForLongPress.currentPressCount = ++pressCount;
|
||||
postDelayed(pendingCheckForLongPress, ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
class CheckForLongPress implements Runnable {
|
||||
public int currentPressCount;
|
||||
|
||||
public void run() {
|
||||
if (checkingForLongPress && getParent() != null && currentPressCount == pressCount) {
|
||||
if (delegate != null) {
|
||||
checkingForLongPress = false;
|
||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
onTouchEvent(event);
|
||||
event.recycle();
|
||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
delegate.didLongPressed(ChatBaseCell.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChatBaseCell(Context context, boolean isMedia) {
|
||||
super(context);
|
||||
init();
|
||||
chat = isChat;
|
||||
if (chat) {
|
||||
media = isMedia;
|
||||
avatarImage = new ImageReceiver();
|
||||
avatarImage.parentView = new WeakReference<View>(this);
|
||||
onSwipeTouchListener = new OnSwipeTouchListener() {
|
||||
public void onSwipeRight() {
|
||||
if (delegate != null && delegate.onSwipeRight()) {
|
||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
onTouchEvent(event);
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSwipeLeft() {
|
||||
if (delegate != null && delegate.onSwipeLeft()) {
|
||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
onTouchEvent(event);
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
avatarImage.clearImage();
|
||||
currentPhoto = null;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (backgroundDrawableIn == null) {
|
||||
backgroundDrawableIn = getResources().getDrawable(R.drawable.msg_in);
|
||||
backgroundDrawableInSelected = getResources().getDrawable(R.drawable.msg_in_selected);
|
||||
backgroundDrawableOut = getResources().getDrawable(R.drawable.msg_out);
|
||||
backgroundDrawableOutSelected = getResources().getDrawable(R.drawable.msg_out_selected);
|
||||
backgroundMediaDrawableIn = getResources().getDrawable(R.drawable.msg_in_photo);
|
||||
backgroundMediaDrawableInSelected = getResources().getDrawable(R.drawable.msg_in_photo_selected);
|
||||
backgroundMediaDrawableOut = getResources().getDrawable(R.drawable.msg_out_photo);
|
||||
backgroundMediaDrawableOutSelected = getResources().getDrawable(R.drawable.msg_out_photo_selected);
|
||||
checkDrawable = getResources().getDrawable(R.drawable.msg_check);
|
||||
halfCheckDrawable = getResources().getDrawable(R.drawable.msg_halfcheck);
|
||||
clockDrawable = getResources().getDrawable(R.drawable.msg_clock);
|
||||
checkMediaDrawable = getResources().getDrawable(R.drawable.msg_check_w);
|
||||
halfCheckMediaDrawable = getResources().getDrawable(R.drawable.msg_halfcheck_w);
|
||||
clockMediaDrawable = getResources().getDrawable(R.drawable.msg_clock_photo);
|
||||
errorDrawable = getResources().getDrawable(R.drawable.msg_warning);
|
||||
mediaBackgroundDrawable = getResources().getDrawable(R.drawable.phototime);
|
||||
|
||||
timePaintIn = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
|
||||
timePaintIn.setTextSize(Utilities.dp(12));
|
||||
@ -124,6 +206,10 @@ public class ChatBaseCell extends BaseCell {
|
||||
timePaintOut.setTextSize(Utilities.dp(12));
|
||||
timePaintOut.setColor(0xff70b15c);
|
||||
|
||||
timeMediaPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
|
||||
timeMediaPaint.setTextSize(Utilities.dp(12));
|
||||
timeMediaPaint.setColor(0xffffffff);
|
||||
|
||||
namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
|
||||
namePaint.setTextSize(Utilities.dp(15));
|
||||
|
||||
@ -151,7 +237,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
TLRPC.User newUser = MessagesController.getInstance().users.get(currentMessageObject.messageOwner.from_id);
|
||||
TLRPC.FileLocation newPhoto = null;
|
||||
|
||||
if (avatarImage != null && newUser != null && newUser.photo != null) {
|
||||
if (isAvatarVisible && newUser != null && newUser.photo != null) {
|
||||
newPhoto = newUser.photo.photo_small;
|
||||
}
|
||||
|
||||
@ -160,7 +246,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
|
||||
String newNameString = null;
|
||||
if (drawName && chat && newUser != null && !currentMessageObject.messageOwner.out) {
|
||||
if (drawName && isChat && newUser != null && !currentMessageObject.messageOwner.out) {
|
||||
newNameString = Utilities.formatName(newUser.first_name, newUser.last_name);
|
||||
}
|
||||
|
||||
@ -180,6 +266,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
currentMessageObject = messageObject;
|
||||
isPressed = false;
|
||||
isCheckPressed = true;
|
||||
isAvatarVisible = false;
|
||||
wasLayout = false;
|
||||
|
||||
if (currentMessageObject.messageOwner.id < 0 && currentMessageObject.messageOwner.send_state != MessagesController.MESSAGE_SEND_STATE_SEND_ERROR && currentMessageObject.messageOwner.send_state != MessagesController.MESSAGE_SEND_STATE_SENT) {
|
||||
@ -189,7 +276,8 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
|
||||
currentUser = MessagesController.getInstance().users.get(messageObject.messageOwner.from_id);
|
||||
if (avatarImage != null) {
|
||||
if (isChat && !messageObject.messageOwner.out) {
|
||||
isAvatarVisible = true;
|
||||
if (currentUser != null) {
|
||||
if (currentUser.photo != null) {
|
||||
currentPhoto = currentUser.photo.photo_small;
|
||||
@ -200,18 +288,22 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
}
|
||||
|
||||
if (!media) {
|
||||
if (currentMessageObject.messageOwner.out) {
|
||||
currentTimePaint = timePaintOut;
|
||||
} else {
|
||||
currentTimePaint = timePaintIn;
|
||||
}
|
||||
} else {
|
||||
currentTimePaint = timeMediaPaint;
|
||||
}
|
||||
|
||||
currentTimeString = LocaleController.formatterDay.format((long) (currentMessageObject.messageOwner.date) * 1000);
|
||||
timeWidth = (int)Math.ceil(currentTimePaint.measureText(currentTimeString));
|
||||
|
||||
namesOffset = 0;
|
||||
|
||||
if (drawName && chat && currentUser != null && !currentMessageObject.messageOwner.out) {
|
||||
if (drawName && isChat && currentUser != null && !currentMessageObject.messageOwner.out) {
|
||||
currentNameString = Utilities.formatName(currentUser.first_name, currentUser.last_name);
|
||||
nameWidth = getMaxNameWidth();
|
||||
|
||||
@ -269,13 +361,39 @@ public class ChatBaseCell extends BaseCell {
|
||||
return backgroundWidth - Utilities.dp(8);
|
||||
}
|
||||
|
||||
protected void startCheckLongPress() {
|
||||
if (checkingForLongPress) {
|
||||
return;
|
||||
}
|
||||
checkingForLongPress = true;
|
||||
if (pendingCheckForTap == null) {
|
||||
pendingCheckForTap = new CheckForTap();
|
||||
}
|
||||
postDelayed(pendingCheckForTap, ViewConfiguration.getTapTimeout());
|
||||
}
|
||||
|
||||
protected void cancelCheckLongPress() {
|
||||
checkingForLongPress = false;
|
||||
if (pendingCheckForLongPress != null) {
|
||||
removeCallbacks(pendingCheckForLongPress);
|
||||
}
|
||||
if (pendingCheckForTap != null) {
|
||||
removeCallbacks(pendingCheckForTap);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkSwipes(MotionEvent event) {
|
||||
onSwipeTouchListener.onTouch(this, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean result = false;
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
if (avatarImage != null && x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH) {
|
||||
if (delegate == null || delegate.canPerformActions()) {
|
||||
if (isAvatarVisible && x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH) {
|
||||
avatarPressed = true;
|
||||
result = true;
|
||||
} else if (drawForwardedName && forwardedNameLayout != null) {
|
||||
@ -284,7 +402,15 @@ public class ChatBaseCell extends BaseCell {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
} else if (avatarPressed) {
|
||||
if (result) {
|
||||
startCheckLongPress();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (event.getAction() != MotionEvent.ACTION_MOVE) {
|
||||
cancelCheckLongPress();
|
||||
}
|
||||
if (avatarPressed) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
avatarPressed = false;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
@ -294,7 +420,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
avatarPressed = false;
|
||||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (avatarImage != null && !(x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH)) {
|
||||
if (isAvatarVisible && !(x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH)) {
|
||||
avatarPressed = false;
|
||||
}
|
||||
}
|
||||
@ -313,6 +439,7 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -329,13 +456,21 @@ public class ChatBaseCell extends BaseCell {
|
||||
layoutHeight = getMeasuredHeight();
|
||||
|
||||
timeLayout = new StaticLayout(currentTimeString, currentTimePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
if (!media) {
|
||||
if (!currentMessageObject.messageOwner.out) {
|
||||
timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (chat ? Utilities.dp(52) : 0);
|
||||
timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (isChat ? Utilities.dp(52) : 0);
|
||||
} else {
|
||||
timeX = layoutWidth - timeWidth - Utilities.dpf(38.5f);
|
||||
}
|
||||
} else {
|
||||
if (!currentMessageObject.messageOwner.out) {
|
||||
timeX = backgroundWidth - Utilities.dp(4) - timeWidth + (isChat ? Utilities.dp(52) : 0);
|
||||
} else {
|
||||
timeX = layoutWidth - timeWidth - Utilities.dpf(42.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (avatarImage != null) {
|
||||
if (isAvatarVisible) {
|
||||
avatarImage.imageX = Utilities.dp(6);
|
||||
avatarImage.imageY = layoutHeight - Utilities.dp(45);
|
||||
avatarImage.imageW = Utilities.dp(42);
|
||||
@ -346,6 +481,11 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAfterBackgroundDraw(Canvas canvas) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (currentMessageObject == null) {
|
||||
@ -353,36 +493,54 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
|
||||
if (!wasLayout) {
|
||||
requestFocus();
|
||||
requestLayout();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatarImage != null) {
|
||||
if (isAvatarVisible) {
|
||||
avatarImage.draw(canvas, Utilities.dp(6), layoutHeight - Utilities.dp(45), Utilities.dp(42), Utilities.dp(42));
|
||||
}
|
||||
|
||||
Drawable currentBackgroundDrawable = null;
|
||||
if (currentMessageObject.messageOwner.out) {
|
||||
if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) {
|
||||
if (!media) {
|
||||
currentBackgroundDrawable = backgroundDrawableOutSelected;
|
||||
} else {
|
||||
currentBackgroundDrawable = backgroundDrawableOut;
|
||||
currentBackgroundDrawable = backgroundMediaDrawableOutSelected;
|
||||
}
|
||||
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
} else {
|
||||
if (!media) {
|
||||
currentBackgroundDrawable = backgroundDrawableOut;
|
||||
} else {
|
||||
currentBackgroundDrawable = backgroundMediaDrawableOut;
|
||||
}
|
||||
}
|
||||
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : Utilities.dp(9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
} else {
|
||||
if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) {
|
||||
if (!media) {
|
||||
currentBackgroundDrawable = backgroundDrawableInSelected;
|
||||
} else {
|
||||
currentBackgroundDrawable = backgroundDrawableIn;
|
||||
currentBackgroundDrawable = backgroundMediaDrawableInSelected;
|
||||
}
|
||||
if (chat) {
|
||||
setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
} else {
|
||||
setDrawableBounds(currentBackgroundDrawable, 0, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
if (!media) {
|
||||
currentBackgroundDrawable = backgroundDrawableIn;
|
||||
} else {
|
||||
currentBackgroundDrawable = backgroundMediaDrawableIn;
|
||||
}
|
||||
}
|
||||
if (isChat) {
|
||||
setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52 + (!media ? 0 : 9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
} else {
|
||||
setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : Utilities.dp(9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
|
||||
}
|
||||
}
|
||||
currentBackgroundDrawable.draw(canvas);
|
||||
|
||||
onAfterBackgroundDraw(canvas);
|
||||
|
||||
if (drawName && nameLayout != null) {
|
||||
canvas.save();
|
||||
canvas.translate(currentBackgroundDrawable.getBounds().left + Utilities.dp(19) - nameOffsetX, Utilities.dp(10));
|
||||
@ -407,10 +565,20 @@ public class ChatBaseCell extends BaseCell {
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (media) {
|
||||
setDrawableBounds(mediaBackgroundDrawable, timeX - Utilities.dp(3), layoutHeight - Utilities.dpf(27.5f), timeWidth + Utilities.dp(6 + (currentMessageObject.messageOwner.out ? 20 : 0)), Utilities.dpf(16.5f));
|
||||
mediaBackgroundDrawable.draw(canvas);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(timeX, layoutHeight - Utilities.dpf(12.0f) - timeLayout.getHeight());
|
||||
timeLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
} else {
|
||||
canvas.save();
|
||||
canvas.translate(timeX, layoutHeight - Utilities.dpf(6.5f) - timeLayout.getHeight());
|
||||
timeLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (currentMessageObject.messageOwner.out) {
|
||||
boolean drawCheck1 = false;
|
||||
@ -441,24 +609,48 @@ public class ChatBaseCell extends BaseCell {
|
||||
}
|
||||
|
||||
if (drawClock) {
|
||||
if (!media) {
|
||||
setDrawableBounds(clockDrawable, layoutWidth - Utilities.dpf(18.5f) - clockDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - clockDrawable.getIntrinsicHeight());
|
||||
clockDrawable.draw(canvas);
|
||||
} else {
|
||||
setDrawableBounds(clockMediaDrawable, layoutWidth - Utilities.dpf(22.0f) - clockMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - clockMediaDrawable.getIntrinsicHeight());
|
||||
clockMediaDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
if (drawCheck2) {
|
||||
if (!media) {
|
||||
if (drawCheck1) {
|
||||
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(22.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
|
||||
} else {
|
||||
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(18.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
|
||||
}
|
||||
checkDrawable.draw(canvas);
|
||||
} else {
|
||||
if (drawCheck1) {
|
||||
setDrawableBounds(checkMediaDrawable, layoutWidth - Utilities.dpf(26.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight());
|
||||
} else {
|
||||
setDrawableBounds(checkMediaDrawable, layoutWidth - Utilities.dpf(22.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight());
|
||||
}
|
||||
checkMediaDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
if (drawCheck1) {
|
||||
if (!media) {
|
||||
setDrawableBounds(halfCheckDrawable, layoutWidth - Utilities.dp(18) - halfCheckDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - halfCheckDrawable.getIntrinsicHeight());
|
||||
halfCheckDrawable.draw(canvas);
|
||||
} else {
|
||||
setDrawableBounds(halfCheckMediaDrawable, layoutWidth - Utilities.dpf(20.5f) - halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - halfCheckMediaDrawable.getIntrinsicHeight());
|
||||
halfCheckMediaDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
if (drawError) {
|
||||
if (!media) {
|
||||
setDrawableBounds(errorDrawable, layoutWidth - Utilities.dp(18) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(6.5f) - errorDrawable.getIntrinsicHeight());
|
||||
errorDrawable.draw(canvas);
|
||||
} else {
|
||||
setDrawableBounds(errorDrawable, layoutWidth - Utilities.dpf(20.5f) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(12.5f) - errorDrawable.getIntrinsicHeight());
|
||||
errorDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.4.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-2014.
|
||||
*/
|
||||
|
||||
package org.telegram.ui.Cells;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SoundEffectConstants;
|
||||
import android.view.View;
|
||||
|
||||
import org.telegram.messenger.FileLoader;
|
||||
import org.telegram.messenger.MediaController;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.objects.MessageObject;
|
||||
import org.telegram.objects.PhotoObject;
|
||||
import org.telegram.ui.Views.GifDrawable;
|
||||
import org.telegram.ui.Views.ImageReceiver;
|
||||
import org.telegram.ui.Views.ProgressView;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ChatMediaCell extends ChatBaseCell implements MediaController.FileDownloadProgressListener {
|
||||
|
||||
public static interface ChatMediaCellDelegate {
|
||||
public abstract void didPressedImage(ChatBaseCell cell);
|
||||
}
|
||||
|
||||
private static Drawable placeholderInDrawable;
|
||||
private static Drawable placeholderOutDrawable;
|
||||
private static Drawable[][] buttonStatesDrawables = new Drawable[3][2];
|
||||
private static TextPaint infoPaint;
|
||||
|
||||
private GifDrawable gifDrawable = null;
|
||||
|
||||
private int photoWidth;
|
||||
private int photoHeight;
|
||||
private PhotoObject currentPhotoObject;
|
||||
private String currentPhotoFilter;
|
||||
private ImageReceiver photoImage;
|
||||
private ProgressView progressView;
|
||||
public boolean downloadPhotos = true;
|
||||
private boolean progressVisible = false;
|
||||
|
||||
private int TAG;
|
||||
|
||||
private int buttonState = 0;
|
||||
private int buttonPressed = 0;
|
||||
private boolean imagePressed = false;
|
||||
private int buttonX;
|
||||
private int buttonY;
|
||||
|
||||
private StaticLayout infoLayout;
|
||||
protected int infoWidth;
|
||||
private String currentInfoString;
|
||||
|
||||
public ChatMediaCellDelegate mediaDelegate = null;
|
||||
|
||||
public ChatMediaCell(Context context) {
|
||||
super(context, true);
|
||||
|
||||
if (placeholderInDrawable == null) {
|
||||
placeholderInDrawable = getResources().getDrawable(R.drawable.photo_placeholder_in);
|
||||
placeholderOutDrawable = getResources().getDrawable(R.drawable.photo_placeholder_out);
|
||||
buttonStatesDrawables[0][0] = getResources().getDrawable(R.drawable.photoload);
|
||||
buttonStatesDrawables[0][1] = getResources().getDrawable(R.drawable.photoload_pressed);
|
||||
buttonStatesDrawables[1][0] = getResources().getDrawable(R.drawable.photocancel);
|
||||
buttonStatesDrawables[1][1] = getResources().getDrawable(R.drawable.photocancel_pressed);
|
||||
buttonStatesDrawables[2][0] = getResources().getDrawable(R.drawable.photogif);
|
||||
buttonStatesDrawables[2][1] = getResources().getDrawable(R.drawable.photogif_pressed);
|
||||
|
||||
infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
infoPaint.setColor(0xffffffff);
|
||||
infoPaint.setTextSize(Utilities.dp(12));
|
||||
}
|
||||
|
||||
TAG = MediaController.getInstance().generateObserverTag();
|
||||
|
||||
photoImage = new ImageReceiver();
|
||||
photoImage.parentView = new WeakReference<View>(this);
|
||||
progressView = new ProgressView();
|
||||
progressView.setProgressColors(0x802a2a2a, 0xffffffff);
|
||||
}
|
||||
|
||||
public void clearGifImage() {
|
||||
if (currentMessageObject != null && currentMessageObject.type == 8) {
|
||||
gifDrawable = null;
|
||||
buttonState = 2;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (photoImage != null) {
|
||||
photoImage.clearImage();
|
||||
currentPhotoObject = null;
|
||||
}
|
||||
if (gifDrawable != null) {
|
||||
MediaController.getInstance().clearGifDrawable(this);
|
||||
gifDrawable = null;
|
||||
}
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
|
||||
boolean result = false;
|
||||
int side = Utilities.dp(44);
|
||||
checkSwipes(event);
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
if (delegate == null || delegate.canPerformActions()) {
|
||||
if (buttonState != -1 && x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) {
|
||||
buttonPressed = 1;
|
||||
invalidate();
|
||||
result = true;
|
||||
} else if (x >= photoImage.imageX && x <= photoImage.imageX + photoImage.imageW && y >= photoImage.imageY && y <= photoImage.imageY + photoImage.imageH) {
|
||||
imagePressed = true;
|
||||
result = true;
|
||||
}
|
||||
if (result) {
|
||||
startCheckLongPress();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (event.getAction() != MotionEvent.ACTION_MOVE) {
|
||||
cancelCheckLongPress();
|
||||
}
|
||||
if (buttonPressed == 1) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
buttonPressed = 0;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
didPressedButton();
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
buttonPressed = 0;
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) {
|
||||
buttonPressed = 0;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
} else if (imagePressed) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
imagePressed = false;
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
didPressedImage();
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
imagePressed = false;
|
||||
invalidate();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (!(x >= photoImage.imageX && x <= photoImage.imageX + photoImage.imageW && y >= photoImage.imageY && y <= photoImage.imageY + photoImage.imageH)) {
|
||||
imagePressed = false;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
result = super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void didPressedImage() {
|
||||
if (currentMessageObject.type == 1) {
|
||||
if (buttonState == -1) {
|
||||
if (currentMessageObject.type == 1) {
|
||||
if (mediaDelegate != null) {
|
||||
mediaDelegate.didPressedImage(this);
|
||||
}
|
||||
}
|
||||
} else if (buttonState == 0) {
|
||||
didPressedButton();
|
||||
}
|
||||
} else if (currentMessageObject.type == 8) {
|
||||
if (buttonState == -1) {
|
||||
buttonState = 2;
|
||||
if (gifDrawable != null) {
|
||||
gifDrawable.pause();
|
||||
}
|
||||
invalidate();
|
||||
} else if (buttonState == 2 || buttonState == 0) {
|
||||
didPressedButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void didPressedButton() {
|
||||
if (buttonState == 0) {
|
||||
if (currentMessageObject.type == 1) {
|
||||
if (currentMessageObject.imagePreview != null) {
|
||||
photoImage.setImage(currentPhotoObject.photoOwner.location, currentPhotoFilter, new BitmapDrawable(currentMessageObject.imagePreview), currentPhotoObject.photoOwner.size);
|
||||
} else {
|
||||
photoImage.setImage(currentPhotoObject.photoOwner.location, currentPhotoFilter, currentMessageObject.messageOwner.out ? placeholderOutDrawable : placeholderInDrawable, currentPhotoObject.photoOwner.size);
|
||||
}
|
||||
} else if (currentMessageObject.type == 8) {
|
||||
FileLoader.getInstance().loadFile(null, null, currentMessageObject.messageOwner.media.document, null);
|
||||
}
|
||||
progressVisible = true;
|
||||
buttonState = 1;
|
||||
invalidate();
|
||||
} else if (buttonState == 1) {
|
||||
if (currentMessageObject.messageOwner.out && currentMessageObject.messageOwner.send_state == MessagesController.MESSAGE_SEND_STATE_SENDING) {
|
||||
if (delegate != null) {
|
||||
delegate.didPressedCanceSendButton(this);
|
||||
}
|
||||
} else {
|
||||
if (currentMessageObject.type == 1) {
|
||||
FileLoader.getInstance().cancelLoadingForImageView(photoImage);
|
||||
} else if (currentMessageObject.type == 8) {
|
||||
FileLoader.getInstance().cancelLoadFile(null, null, currentMessageObject.messageOwner.media.document, null);
|
||||
}
|
||||
progressVisible = false;
|
||||
buttonState = 0;
|
||||
invalidate();
|
||||
}
|
||||
} else if (buttonState == 2) {
|
||||
if (gifDrawable == null) {
|
||||
gifDrawable = MediaController.getInstance().getGifDrawable(this, true);
|
||||
}
|
||||
if (gifDrawable != null) {
|
||||
gifDrawable.start();
|
||||
gifDrawable.invalidateSelf();
|
||||
buttonState = -1;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUserDataChanged() {
|
||||
return currentPhotoObject == null || super.isUserDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageObject(MessageObject messageObject) {
|
||||
if (currentMessageObject != messageObject || isUserDataChanged()) {
|
||||
super.setMessageObject(messageObject);
|
||||
|
||||
progressVisible = false;
|
||||
buttonState = -1;
|
||||
gifDrawable = null;
|
||||
|
||||
if (messageObject.type == 8) {
|
||||
gifDrawable = MediaController.getInstance().getGifDrawable(this, false);
|
||||
|
||||
String str = Utilities.formatFileSize(messageObject.messageOwner.media.document.size);
|
||||
if (currentInfoString == null || !currentInfoString.equals(str)) {
|
||||
currentInfoString = str;
|
||||
infoWidth = (int) Math.ceil(infoPaint.measureText(currentInfoString));
|
||||
infoLayout = new StaticLayout(currentInfoString, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
}
|
||||
} else {
|
||||
currentInfoString = null;
|
||||
infoLayout = null;
|
||||
}
|
||||
|
||||
photoWidth = (int) (Math.min(Utilities.displaySize.x, Utilities.displaySize.y) * 0.7f);
|
||||
photoHeight = photoWidth + Utilities.dp(100);
|
||||
if (messageObject.type == 6 || messageObject.type == 7) {
|
||||
photoWidth = (int) (Math.min(Utilities.displaySize.x, Utilities.displaySize.y) / 2.5f);
|
||||
photoHeight = photoWidth + 100;
|
||||
}
|
||||
if (photoWidth > 800) {
|
||||
photoWidth = 800;
|
||||
}
|
||||
if (photoHeight > 800) {
|
||||
photoHeight = 800;
|
||||
}
|
||||
|
||||
currentPhotoObject = PhotoObject.getClosestImageWithSize(messageObject.photoThumbs, photoWidth, photoHeight);
|
||||
if (currentPhotoObject != null) {
|
||||
float scale = (float) currentPhotoObject.photoOwner.w / (float) photoWidth;
|
||||
|
||||
int w = (int) (currentPhotoObject.photoOwner.w / scale);
|
||||
int h = (int) (currentPhotoObject.photoOwner.h / scale);
|
||||
if (h > photoHeight) {
|
||||
float scale2 = h;
|
||||
h = photoHeight;
|
||||
scale2 /= h;
|
||||
w = (int) (w / scale2);
|
||||
} else if (h < Utilities.dp(120)) {
|
||||
h = Utilities.dp(120);
|
||||
float hScale = (float) currentPhotoObject.photoOwner.h / h;
|
||||
if (currentPhotoObject.photoOwner.w / hScale < photoWidth) {
|
||||
w = (int) (currentPhotoObject.photoOwner.w / hScale);
|
||||
}
|
||||
}
|
||||
|
||||
photoWidth = w;
|
||||
photoHeight = h;
|
||||
backgroundWidth = w + Utilities.dp(12);
|
||||
currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (w / Utilities.density), (int) (h / Utilities.density));
|
||||
|
||||
if (currentPhotoObject.image != null) {
|
||||
photoImage.setImageBitmap(currentPhotoObject.image);
|
||||
} else {
|
||||
boolean photoExist = true;
|
||||
String fileName = MessageObject.getAttachFileName(currentPhotoObject.photoOwner);
|
||||
if (messageObject.type == 1) {
|
||||
File cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
if (!cacheFile.exists()) {
|
||||
photoExist = false;
|
||||
} else {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
}
|
||||
}
|
||||
if (photoExist || downloadPhotos) {
|
||||
if (messageObject.imagePreview != null) {
|
||||
photoImage.setImage(currentPhotoObject.photoOwner.location, currentPhotoFilter, new BitmapDrawable(messageObject.imagePreview), currentPhotoObject.photoOwner.size);
|
||||
} else {
|
||||
photoImage.setImage(currentPhotoObject.photoOwner.location, currentPhotoFilter, messageObject.messageOwner.out ? placeholderOutDrawable : placeholderInDrawable, currentPhotoObject.photoOwner.size);
|
||||
}
|
||||
} else {
|
||||
if (messageObject.imagePreview != null) {
|
||||
photoImage.setImageBitmap(messageObject.imagePreview);
|
||||
} else {
|
||||
photoImage.setImageBitmap(messageObject.messageOwner.out ? placeholderOutDrawable : placeholderInDrawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
photoImage.setImageBitmap(messageObject.messageOwner.out ? placeholderOutDrawable : placeholderInDrawable);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
/*if ((type == 6 || type == 7) && videoTimeText != null) {
|
||||
int duration = message.messageOwner.media.video.duration;
|
||||
int minutes = duration / 60;
|
||||
int seconds = duration - minutes * 60;
|
||||
videoTimeText.setText(String.format("%d:%02d", minutes, seconds));
|
||||
}*/
|
||||
}
|
||||
updateButtonState();
|
||||
}
|
||||
|
||||
public void updateButtonState() {
|
||||
String fileName = null;
|
||||
File cacheFile = null;
|
||||
if (currentMessageObject.type == 1) {
|
||||
if (currentPhotoObject == null) {
|
||||
return;
|
||||
}
|
||||
fileName = MessageObject.getAttachFileName(currentPhotoObject.photoOwner);
|
||||
cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
} else if (currentMessageObject.type == 8) {
|
||||
if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) {
|
||||
File f = new File(currentMessageObject.messageOwner.attachPath);
|
||||
if (f.exists()) {
|
||||
fileName = currentMessageObject.messageOwner.attachPath;
|
||||
cacheFile = f;
|
||||
}
|
||||
} else {
|
||||
fileName = currentMessageObject.getFileName();
|
||||
cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
}
|
||||
}
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
if (currentMessageObject.messageOwner.out && currentMessageObject.messageOwner.send_state == MessagesController.MESSAGE_SEND_STATE_SENDING) {
|
||||
if (currentMessageObject.messageOwner.attachPath != null) {
|
||||
MediaController.getInstance().addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, this);
|
||||
progressVisible = true;
|
||||
buttonState = 1;
|
||||
Float progress = FileLoader.getInstance().fileProgresses.get(currentMessageObject.messageOwner.attachPath);
|
||||
if (progress != null) {
|
||||
progressView.setProgress(progress);
|
||||
} else {
|
||||
progressView.setProgress(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentMessageObject.messageOwner.attachPath != null) {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
}
|
||||
if (cacheFile.exists() && cacheFile.length() == 0) {
|
||||
cacheFile.delete();
|
||||
}
|
||||
if (!cacheFile.exists()) {
|
||||
MediaController.getInstance().addLoadingFileObserver(fileName, this);
|
||||
if (!FileLoader.getInstance().isLoadingFile(fileName)) {
|
||||
if (currentMessageObject.type != 1 || !downloadPhotos) {
|
||||
buttonState = 0;
|
||||
progressVisible = false;
|
||||
} else {
|
||||
buttonState = -1;
|
||||
progressVisible = true;
|
||||
}
|
||||
progressView.setProgress(0);
|
||||
} else {
|
||||
if (currentMessageObject.type != 1 || !downloadPhotos) {
|
||||
buttonState = 1;
|
||||
} else {
|
||||
buttonState = -1;
|
||||
}
|
||||
progressVisible = true;
|
||||
Float progress = FileLoader.getInstance().fileProgresses.get(fileName);
|
||||
if (progress != null) {
|
||||
progressView.setProgress(progress);
|
||||
} else {
|
||||
progressView.setProgress(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MediaController.getInstance().removeLoadingFileObserver(this);
|
||||
progressVisible = false;
|
||||
if (currentMessageObject.type == 8 && (gifDrawable == null || gifDrawable != null && !gifDrawable.isRunning())) {
|
||||
buttonState = 2;
|
||||
} else {
|
||||
buttonState = -1;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), photoHeight + Utilities.dp(14));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
if (currentMessageObject.messageOwner.out) {
|
||||
photoImage.imageX = layoutWidth - backgroundWidth - Utilities.dp(3);
|
||||
} else {
|
||||
if (isChat) {
|
||||
photoImage.imageX = Utilities.dp(67);
|
||||
} else {
|
||||
photoImage.imageX = Utilities.dp(15);
|
||||
}
|
||||
}
|
||||
photoImage.imageY = Utilities.dp(7);
|
||||
photoImage.imageW = photoWidth;
|
||||
photoImage.imageH = photoHeight;
|
||||
|
||||
progressView.width = timeX - photoImage.imageX - Utilities.dpf(23.0f);
|
||||
progressView.height = Utilities.dp(3);
|
||||
progressView.progressHeight = Utilities.dp(3);
|
||||
|
||||
int size = Utilities.dp(44);
|
||||
buttonX = (int)(photoImage.imageX + (photoWidth - size) / 2.0f);
|
||||
buttonY = (int)(photoImage.imageY + (photoHeight - size) / 2.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterBackgroundDraw(Canvas canvas) {
|
||||
if (gifDrawable != null) {
|
||||
canvas.save();
|
||||
gifDrawable.setBounds(photoImage.imageX, photoImage.imageY, photoImage.imageX + photoWidth, photoImage.imageY + photoHeight);
|
||||
gifDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
} else {
|
||||
photoImage.draw(canvas, photoImage.imageX, photoImage.imageY, photoWidth, photoHeight);
|
||||
}
|
||||
|
||||
if (progressVisible) {
|
||||
setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + Utilities.dp(4), layoutHeight - Utilities.dpf(27.5f), progressView.width + Utilities.dp(12), Utilities.dpf(16.5f));
|
||||
mediaBackgroundDrawable.draw(canvas);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(photoImage.imageX + Utilities.dp(10), layoutHeight - Utilities.dpf(21.0f));
|
||||
progressView.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (buttonState >= 0 && buttonState < 3) {
|
||||
Drawable currentButtonDrawable = buttonStatesDrawables[buttonState][buttonPressed];
|
||||
setDrawableBounds(currentButtonDrawable, buttonX, buttonY);
|
||||
currentButtonDrawable.draw(canvas);
|
||||
}
|
||||
|
||||
if (infoLayout != null && (buttonState == 1 || buttonState == 0)) {
|
||||
setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + Utilities.dp(4), photoImage.imageY + Utilities.dp(4), infoWidth + Utilities.dp(8), Utilities.dpf(16.5f));
|
||||
mediaBackgroundDrawable.draw(canvas);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(photoImage.imageX + Utilities.dp(8), photoImage.imageY + Utilities.dpf(5.5f));
|
||||
infoLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailedDownload(String fileName) {
|
||||
updateButtonState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccessDownload(String fileName) {
|
||||
updateButtonState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressDownload(String fileName, float progress) {
|
||||
progressVisible = true;
|
||||
progressView.setProgress(progress);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressUpload(String fileName, float progress, boolean isEncrypted) {
|
||||
progressView.setProgress(progress);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObserverTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
@ -28,8 +28,8 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
private int firstVisibleBlockNum = 0;
|
||||
private int totalVisibleBlocksCount = 0;
|
||||
|
||||
public ChatMessageCell(Context context, boolean isChat) {
|
||||
super(context, isChat);
|
||||
public ChatMessageCell(Context context) {
|
||||
super(context, false);
|
||||
drawForwardedName = true;
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
}
|
||||
pressedLink = null;
|
||||
int maxWidth;
|
||||
if (chat) {
|
||||
if (isChat && !messageObject.messageOwner.out) {
|
||||
maxWidth = Utilities.displaySize.x - Utilities.dp(122);
|
||||
drawName = true;
|
||||
} else {
|
||||
@ -180,7 +180,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
textX = layoutWidth - backgroundWidth + Utilities.dp(10);
|
||||
textY = Utilities.dp(10) + namesOffset;
|
||||
} else {
|
||||
textX = Utilities.dp(19) + (chat ? Utilities.dp(52) : 0);
|
||||
textX = Utilities.dp(19) + (isChat ? Utilities.dp(52) : 0);
|
||||
textY = Utilities.dp(10) + namesOffset;
|
||||
}
|
||||
}
|
||||
@ -196,7 +196,7 @@ public class ChatMessageCell extends ChatBaseCell {
|
||||
textX = layoutWidth - backgroundWidth + Utilities.dp(10);
|
||||
textY = Utilities.dp(10) + namesOffset;
|
||||
} else {
|
||||
textX = Utilities.dp(19) + (chat ? Utilities.dp(52) : 0);
|
||||
textX = Utilities.dp(19) + (isChat ? Utilities.dp(52) : 0);
|
||||
textY = Utilities.dp(10) + namesOffset;
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,15 @@ public class ChatOrUserCell extends BaseCell {
|
||||
update(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (avatarImage != null) {
|
||||
avatarImage.clearImage();
|
||||
lastAvatar = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Utilities.dp(64));
|
||||
|
@ -152,6 +152,14 @@ public class DialogCell extends BaseCell {
|
||||
update(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (avatarImage != null) {
|
||||
avatarImage.clearImage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Utilities.dp(70));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@ import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.internal.view.SupportMenuItem;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@ -163,6 +164,9 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
|
||||
editor.commit();
|
||||
listView.invalidateViews();
|
||||
} else if (i == 3) {
|
||||
if (parentActivity == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||
tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
|
||||
@ -187,7 +191,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
|
||||
}
|
||||
|
||||
tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound);
|
||||
startActivityForResult(tmpIntent, 15);
|
||||
parentActivity.startActivityForResult(tmpIntent, 3);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -247,11 +251,10 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
avatarUpdater.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == 15) {
|
||||
if (requestCode == 3) {
|
||||
Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
||||
String name = null;
|
||||
if (ringtone != null && parentActivity != null) {
|
||||
@ -481,17 +484,22 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.group_profile_menu, menu);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.findItem(R.id.block_user);
|
||||
TextView doneTextView = (TextView)doneItem.getActionView().findViewById(R.id.done_button);
|
||||
doneTextView.setText(LocaleController.getString("AddMember", R.string.AddMember));
|
||||
doneTextView.setOnClickListener(new View.OnClickListener() {
|
||||
SupportMenuItem item = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, LocaleController.getString("AddMember", R.string.AddMember));
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
LayoutInflater li = (LayoutInflater)ApplicationLoader.applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
item.setActionView(R.layout.group_profile_add_member_layout);
|
||||
|
||||
TextView textView = (TextView)item.getActionView().findViewById(R.id.done_button);
|
||||
if (textView != null) {
|
||||
textView.setText(LocaleController.getString("AddMember", R.string.AddMember));
|
||||
textView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
openAddMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ListAdapter extends BaseAdapter {
|
||||
private Context mContext;
|
||||
|
@ -306,7 +306,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
||||
private void didSelectResult(final TLRPC.User user, boolean useAlert) {
|
||||
if (useAlert && selectAlertString != 0) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setTitle(R.string.AppName);
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setMessage(LocaleController.formatString(selectAlertStringDesc, selectAlertString, Utilities.formatName(user.first_name, user.last_name)));
|
||||
builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
@ -400,9 +400,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
inflater.inflate(R.menu.contacts_menu, menu);
|
||||
searchItem = (SupportMenuItem)menu.findItem(R.id.messages_list_menu_search);
|
||||
searchView = (SearchView)searchItem.getActionView();
|
||||
searchItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, LocaleController.getString("Search", R.string.Search)).setIcon(R.drawable.ic_ab_search);
|
||||
searchItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS|SupportMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
searchItem.setActionView(searchView = new SearchView(parentActivity));
|
||||
|
||||
TextView textView = (TextView) searchView.findViewById(R.id.search_src_text);
|
||||
if (textView != null) {
|
||||
|
@ -19,7 +19,6 @@ import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -191,11 +190,9 @@ public class CountrySelectActivity extends ActionBarActivity {
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
|
||||
inflater.inflate(R.menu.contacts_menu, menu);
|
||||
searchItem = (SupportMenuItem)menu.findItem(R.id.messages_list_menu_search);
|
||||
searchView = (SearchView)searchItem.getActionView();
|
||||
searchItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, LocaleController.getString("Search", R.string.Search)).setIcon(R.drawable.ic_ab_search);
|
||||
searchItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS|SupportMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
searchItem.setActionView(searchView = new SearchView(this));
|
||||
|
||||
TextView textView = (TextView) searchView.findViewById(R.id.search_src_text);
|
||||
if (textView != null) {
|
||||
|
@ -345,7 +345,7 @@ public class DocumentSelectActivity extends BaseFragment {
|
||||
|
||||
private void showErrorBox(String error){
|
||||
new AlertDialog.Builder(parentActivity)
|
||||
.setTitle(R.string.AppName)
|
||||
.setTitle(LocaleController.getString("AppName", R.string.AppName))
|
||||
.setMessage(error)
|
||||
.setPositiveButton(R.string.OK, null)
|
||||
.show();
|
||||
|
@ -18,7 +18,6 @@ import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.Display;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -82,6 +81,9 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
|
||||
|
||||
public static int needShowAllMedia = 2000;
|
||||
|
||||
private final static int gallery_menu_save = 1;
|
||||
private final static int gallery_menu_showall = 2;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -640,11 +642,9 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
if (withoutBottom) {
|
||||
inflater.inflate(R.menu.gallery_save_only_menu, menu);
|
||||
} else {
|
||||
inflater.inflate(R.menu.gallery_menu, menu);
|
||||
menu.add(Menu.NONE, gallery_menu_save, Menu.NONE, LocaleController.getString("SaveToGallery", R.string.SaveToGallery));
|
||||
if (!withoutBottom) {
|
||||
menu.add(Menu.NONE, gallery_menu_showall, Menu.NONE, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia));
|
||||
}
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
@ -721,7 +721,7 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
|
||||
finish();
|
||||
System.gc();
|
||||
break;
|
||||
case R.id.gallery_menu_save:
|
||||
case gallery_menu_save:
|
||||
if (currentFileName == null) {
|
||||
return;
|
||||
}
|
||||
@ -737,7 +737,7 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
|
||||
// startActivityForResult(intent, 10);
|
||||
// break;
|
||||
// }
|
||||
case R.id.gallery_menu_showall: {
|
||||
case gallery_menu_showall: {
|
||||
if (fromAll) {
|
||||
finish();
|
||||
} else {
|
||||
|
@ -421,8 +421,10 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.group_create_menu, menu);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.findItem(R.id.done_menu_item);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, null);
|
||||
doneItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
doneItem.setActionView(R.layout.group_create_done_layout);
|
||||
|
||||
TextView doneTextView = (TextView)doneItem.getActionView().findViewById(R.id.done_button);
|
||||
doneTextView.setText(LocaleController.getString("Next", R.string.Next));
|
||||
doneTextView.setOnClickListener(new View.OnClickListener() {
|
||||
@ -431,11 +433,12 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
|
||||
if (!selectedContacts.isEmpty()) {
|
||||
ArrayList<Integer> result = new ArrayList<Integer>();
|
||||
result.addAll(selectedContacts.keySet());
|
||||
NotificationCenter.getInstance().addToMemCache(2, result);
|
||||
} else {
|
||||
return;
|
||||
Bundle args = new Bundle();
|
||||
args.putIntegerArrayList("result", result);
|
||||
GroupCreateFinalActivity fragment = new GroupCreateFinalActivity();
|
||||
fragment.setArguments(args);
|
||||
((LaunchActivity)parentActivity).presentFragment(fragment, "group_craate_final", false);
|
||||
}
|
||||
((LaunchActivity)parentActivity).presentFragment(new GroupCreateFinalActivity(), "group_craate_final", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.telegram.messenger.ConnectionsManager;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessagesStorage;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
@ -42,10 +43,11 @@ import org.telegram.ui.Views.PinnedHeaderListView;
|
||||
import org.telegram.ui.Views.SectionedBaseAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class GroupCreateFinalActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, AvatarUpdater.AvatarUpdaterDelegate {
|
||||
private PinnedHeaderListView listView;
|
||||
private TextView nameTextView;
|
||||
private EditText nameTextView;
|
||||
private TLRPC.FileLocation avatar;
|
||||
private TLRPC.InputFile uploadedAvatar;
|
||||
private ArrayList<Integer> selectedContacts;
|
||||
@ -54,6 +56,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
||||
private boolean donePressed;
|
||||
private AvatarUpdater avatarUpdater = new AvatarUpdater();
|
||||
private ProgressDialog progressDialog = null;
|
||||
private String nameToSet = null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@ -64,7 +67,40 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
||||
NotificationCenter.getInstance().addObserver(this, MessagesController.chatDidFailCreate);
|
||||
avatarUpdater.parentFragment = this;
|
||||
avatarUpdater.delegate = this;
|
||||
selectedContacts = (ArrayList<Integer>)NotificationCenter.getInstance().getFromMemCache(2);
|
||||
selectedContacts = getArguments().getIntegerArrayList("result");
|
||||
final ArrayList<Integer> usersToLoad = new ArrayList<Integer>();
|
||||
for (Integer uid : selectedContacts) {
|
||||
if (MessagesController.getInstance().users.get(uid) == null) {
|
||||
usersToLoad.add(uid);
|
||||
}
|
||||
}
|
||||
if (!usersToLoad.isEmpty()) {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
|
||||
final boolean[] error = new boolean[1];
|
||||
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
users.addAll(MessagesStorage.getInstance().getUsers(usersToLoad, error));
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
if (error[0]) {
|
||||
return false;
|
||||
}
|
||||
if (!users.isEmpty()) {
|
||||
for (TLRPC.User user : users) {
|
||||
MessagesController.getInstance().users.putIfAbsent(user.id, user);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -125,6 +161,10 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
||||
|
||||
nameTextView = (EditText)fragmentView.findViewById(R.id.bubble_input_text);
|
||||
nameTextView.setHint(LocaleController.getString("EnterGroupNamePlaceholder", R.string.EnterGroupNamePlaceholder));
|
||||
if (nameToSet != null) {
|
||||
nameTextView.setText(nameToSet);
|
||||
nameToSet = null;
|
||||
}
|
||||
listView = (PinnedHeaderListView)fragmentView.findViewById(R.id.listView);
|
||||
listView.setAdapter(new ListAdapter(parentActivity));
|
||||
} else {
|
||||
@ -200,15 +240,44 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
avatarUpdater.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSelfArgs(Bundle args) {
|
||||
if (avatarUpdater != null && avatarUpdater.currentPicturePath != null) {
|
||||
args.putString("path", avatarUpdater.currentPicturePath);
|
||||
}
|
||||
if (nameTextView != null) {
|
||||
String text = nameTextView.getText().toString();
|
||||
if (text != null && text.length() != 0) {
|
||||
args.putString("nameTextView", text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSelfArgs(Bundle args) {
|
||||
if (avatarUpdater != null) {
|
||||
avatarUpdater.currentPicturePath = args.getString("path");
|
||||
}
|
||||
String text = args.getString("nameTextView");
|
||||
if (text != null) {
|
||||
if (nameTextView != null) {
|
||||
nameTextView.setText(text);
|
||||
} else {
|
||||
nameToSet = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.group_create_menu, menu);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.findItem(R.id.done_menu_item);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, null);
|
||||
doneItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
doneItem.setActionView(R.layout.group_create_done_layout);
|
||||
|
||||
TextView doneTextView = (TextView)doneItem.getActionView().findViewById(R.id.done_button);
|
||||
doneTextView.setText(LocaleController.getString("Done", R.string.Done));
|
||||
doneTextView.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -8,7 +8,9 @@
|
||||
|
||||
package org.telegram.ui;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.internal.view.SupportMenuItem;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
@ -114,10 +116,62 @@ public class LanguageSelectActivity extends BaseFragment {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (searchItem != null && searchItem.isActionViewExpanded()) {
|
||||
searchItem.collapseActionView();
|
||||
}
|
||||
finishFragment();
|
||||
}
|
||||
});
|
||||
|
||||
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
if (parentActivity == null) {
|
||||
return false;
|
||||
}
|
||||
LocaleController.LocaleInfo localeInfo = null;
|
||||
if (searching && searchWas) {
|
||||
if (i >= 0 && i < searchResult.size()) {
|
||||
localeInfo = searchResult.get(i);
|
||||
}
|
||||
} else {
|
||||
if (i >= 0 && i < LocaleController.getInstance().sortedLanguages.size()) {
|
||||
localeInfo = LocaleController.getInstance().sortedLanguages.get(i);
|
||||
}
|
||||
}
|
||||
if (localeInfo == null || localeInfo.pathToFile == null) {
|
||||
return false;
|
||||
}
|
||||
final LocaleController.LocaleInfo finalLocaleInfo = localeInfo;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setMessage(LocaleController.getString("DeleteLocalization", R.string.DeleteLocalization));
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (LocaleController.getInstance().deleteLanguage(finalLocaleInfo)) {
|
||||
if (searchResult != null) {
|
||||
searchResult.remove(finalLocaleInfo);
|
||||
}
|
||||
if (listAdapter != null) {
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (searchListViewAdapter != null) {
|
||||
searchListViewAdapter.notifyDataSetChanged();
|
||||
}
|
||||
applySelfActionBar();
|
||||
if (searchItem != null && searchItem.isActionViewExpanded()) {
|
||||
searchItem.collapseActionView();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
listView.setOnTouchListener(new OnSwipeTouchListener() {
|
||||
public void onSwipeRight() {
|
||||
finishFragment(true);
|
||||
@ -184,11 +238,9 @@ public class LanguageSelectActivity extends BaseFragment {
|
||||
int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case android.R.id.home:
|
||||
if (searchItem != null) {
|
||||
if (searchItem.isActionViewExpanded()) {
|
||||
if (searchItem != null && searchItem.isActionViewExpanded()) {
|
||||
searchItem.collapseActionView();
|
||||
}
|
||||
}
|
||||
finishFragment();
|
||||
break;
|
||||
}
|
||||
@ -197,9 +249,9 @@ public class LanguageSelectActivity extends BaseFragment {
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.contacts_menu, menu);
|
||||
searchItem = (SupportMenuItem)menu.findItem(R.id.messages_list_menu_search);
|
||||
searchView = (SearchView)searchItem.getActionView();
|
||||
searchItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, LocaleController.getString("Search", R.string.Search)).setIcon(R.drawable.ic_ab_search);
|
||||
searchItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS|SupportMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
searchItem.setActionView(searchView = new SearchView(parentActivity));
|
||||
|
||||
TextView textView = (TextView) searchView.findViewById(R.id.search_src_text);
|
||||
if (textView != null) {
|
||||
|
@ -65,8 +65,8 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
private String videoPath = null;
|
||||
private String sendingText = null;
|
||||
private String documentPath = null;
|
||||
private Uri[] imagesPathArray = null;
|
||||
private String[] documentsPathArray = null;
|
||||
private ArrayList<Uri> imagesPathArray = null;
|
||||
private ArrayList<String> documentsPathArray = null;
|
||||
private ArrayList<TLRPC.User> contactsToSend = null;
|
||||
private int currentConnectionState;
|
||||
private View statusView;
|
||||
@ -140,6 +140,46 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
fragment.onFragmentCreate();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
|
||||
try {
|
||||
if (savedInstanceState != null) {
|
||||
String fragmentName = savedInstanceState.getString("fragment");
|
||||
if (fragmentName != null) {
|
||||
Bundle args = savedInstanceState.getBundle("args");
|
||||
if (fragmentName.equals("chat")) {
|
||||
if (args != null) {
|
||||
ChatActivity chat = new ChatActivity();
|
||||
chat.setArguments(args);
|
||||
if (chat.onFragmentCreate()) {
|
||||
ApplicationLoader.fragmentsStack.add(chat);
|
||||
chat.restoreSelfArgs(savedInstanceState);
|
||||
}
|
||||
}
|
||||
} else if (fragmentName.equals("settings")) {
|
||||
SettingsActivity settings = new SettingsActivity();
|
||||
settings.onFragmentCreate();
|
||||
settings.restoreSelfArgs(savedInstanceState);
|
||||
ApplicationLoader.fragmentsStack.add(settings);
|
||||
} else if (fragmentName.equals("group")) {
|
||||
if (args != null) {
|
||||
GroupCreateFinalActivity group = new GroupCreateFinalActivity();
|
||||
group.setArguments(args);
|
||||
if (group.onFragmentCreate()) {
|
||||
group.restoreSelfArgs(savedInstanceState);
|
||||
ApplicationLoader.fragmentsStack.add(group);
|
||||
}
|
||||
}
|
||||
} else if (fragmentName.equals("wallpapers")) {
|
||||
SettingsWallpapersActivity settings = new SettingsWallpapersActivity();
|
||||
settings.onFragmentCreate();
|
||||
settings.restoreSelfArgs(savedInstanceState);
|
||||
ApplicationLoader.fragmentsStack.add(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
handleIntent(getIntent(), false, savedInstanceState != null);
|
||||
@ -289,7 +329,18 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
parcelable = Uri.parse(parcelable.toString());
|
||||
}
|
||||
if (parcelable != null && type != null && type.startsWith("image/")) {
|
||||
photoPath = (Uri)parcelable;
|
||||
if (type.equals("image/gif")) {
|
||||
try {
|
||||
documentPath = Utilities.getPath((Uri)parcelable);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
if (documentPath == null) {
|
||||
photoPath = (Uri) parcelable;
|
||||
}
|
||||
} else {
|
||||
photoPath = (Uri) parcelable;
|
||||
}
|
||||
} else {
|
||||
path = Utilities.getPath((Uri)parcelable);
|
||||
if (path != null) {
|
||||
@ -316,31 +367,42 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
String type = intent.getType();
|
||||
if (uris != null) {
|
||||
if (type != null && type.startsWith("image/")) {
|
||||
Uri[] uris2 = new Uri[uris.size()];
|
||||
for (int i = 0; i < uris2.length; i++) {
|
||||
Parcelable parcelable = uris.get(i);
|
||||
for (Parcelable parcelable : uris) {
|
||||
if (!(parcelable instanceof Uri)) {
|
||||
parcelable = Uri.parse(parcelable.toString());
|
||||
}
|
||||
uris2[i] = (Uri)parcelable;
|
||||
if (type.equals("image/gif")) {
|
||||
if (documentsPathArray == null) {
|
||||
documentsPathArray = new ArrayList<String>();
|
||||
}
|
||||
try {
|
||||
documentsPathArray.add(Utilities.getPath((Uri) parcelable));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
imagesPathArray = uris2;
|
||||
} else {
|
||||
String[] uris2 = new String[uris.size()];
|
||||
for (int i = 0; i < uris2.length; i++) {
|
||||
Parcelable parcelable = uris.get(i);
|
||||
if (imagesPathArray == null) {
|
||||
imagesPathArray = new ArrayList<Uri>();
|
||||
}
|
||||
imagesPathArray.add((Uri) parcelable);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Parcelable parcelable : uris) {
|
||||
if (!(parcelable instanceof Uri)) {
|
||||
parcelable = Uri.parse(parcelable.toString());
|
||||
}
|
||||
String path = Utilities.getPath((Uri)parcelable);
|
||||
String path = Utilities.getPath((Uri) parcelable);
|
||||
if (path != null) {
|
||||
if (path.startsWith("file:")) {
|
||||
path = path.replace("file://", "");
|
||||
}
|
||||
uris2[i] = path;
|
||||
if (documentsPathArray == null) {
|
||||
documentsPathArray = new ArrayList<String>();
|
||||
}
|
||||
documentsPathArray.add(path);
|
||||
}
|
||||
}
|
||||
documentsPathArray = uris2;
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
@ -497,21 +559,27 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
}
|
||||
if (photoPath != null) {
|
||||
fragment.processSendingPhoto(null, photoPath);
|
||||
} else if (videoPath != null) {
|
||||
}
|
||||
if (videoPath != null) {
|
||||
fragment.processSendingVideo(videoPath);
|
||||
} else if (sendingText != null) {
|
||||
}
|
||||
if (sendingText != null) {
|
||||
fragment.processSendingText(sendingText);
|
||||
} else if (documentPath != null) {
|
||||
}
|
||||
if (documentPath != null) {
|
||||
fragment.processSendingDocument(documentPath);
|
||||
} else if (imagesPathArray != null) {
|
||||
}
|
||||
if (imagesPathArray != null) {
|
||||
for (Uri path : imagesPathArray) {
|
||||
fragment.processSendingPhoto(null, path);
|
||||
}
|
||||
} else if (documentsPathArray != null) {
|
||||
}
|
||||
if (documentsPathArray != null) {
|
||||
for (String path : documentsPathArray) {
|
||||
fragment.processSendingDocument(path);
|
||||
}
|
||||
} else if (contactsToSend != null && !contactsToSend.isEmpty()) {
|
||||
}
|
||||
if (contactsToSend != null && !contactsToSend.isEmpty()) {
|
||||
for (TLRPC.User user : contactsToSend) {
|
||||
MessagesController.getInstance().sendMessage(user, dialog_id);
|
||||
}
|
||||
@ -536,6 +604,15 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (ApplicationLoader.fragmentsStack.size() != 0) {
|
||||
BaseFragment fragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
fragment.onActivityResultFragment(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
@ -932,6 +1009,22 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
try {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (!ApplicationLoader.fragmentsStack.isEmpty()) {
|
||||
BaseFragment lastFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
Bundle args = lastFragment.getArguments();
|
||||
if (lastFragment instanceof ChatActivity && args != null) {
|
||||
outState.putBundle("args", args);
|
||||
outState.putString("fragment", "chat");
|
||||
} else if (lastFragment instanceof SettingsActivity) {
|
||||
outState.putString("fragment", "settings");
|
||||
} else if (lastFragment instanceof GroupCreateFinalActivity && args != null) {
|
||||
outState.putBundle("args", args);
|
||||
outState.putString("fragment", "group");
|
||||
} else if (lastFragment instanceof SettingsWallpapersActivity) {
|
||||
outState.putString("fragment", "wallpapers");
|
||||
}
|
||||
lastFragment.saveSelfArgs(outState);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ package org.telegram.ui;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.internal.view.SupportMenuItem;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@ -53,6 +54,11 @@ public class LocationActivity extends BaseFragment implements NotificationCenter
|
||||
private boolean userLocationMoved = false;
|
||||
private boolean firstWas = false;
|
||||
|
||||
private final static int map_to_my_location = 1;
|
||||
private final static int map_list_menu_map = 2;
|
||||
private final static int map_list_menu_satellite = 3;
|
||||
private final static int map_list_menu_hybrid = 4;
|
||||
|
||||
public SupportMapFragment mapFragment = new SupportMapFragment() {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
@ -261,29 +267,34 @@ public class LocationActivity extends BaseFragment implements NotificationCenter
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.location_menu, menu);
|
||||
SupportMenuItem item = (SupportMenuItem)menu.add(Menu.NONE, map_to_my_location, Menu.NONE, LocaleController.getString("MyLocation", R.string.MyLocation)).setIcon(R.drawable.ic_ab_location);
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
menu.add(Menu.NONE, map_list_menu_map, Menu.NONE, LocaleController.getString("Map", R.string.Map));
|
||||
menu.add(Menu.NONE, map_list_menu_satellite, Menu.NONE, LocaleController.getString("Satellite", R.string.Satellite));
|
||||
menu.add(Menu.NONE, map_list_menu_hybrid, Menu.NONE, LocaleController.getString("Hybrid", R.string.Hybrid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case R.id.map_list_menu_map:
|
||||
case map_list_menu_map:
|
||||
if (googleMap != null) {
|
||||
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
|
||||
}
|
||||
break;
|
||||
case R.id.map_list_menu_satellite:
|
||||
case map_list_menu_satellite:
|
||||
if (googleMap != null) {
|
||||
googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
|
||||
}
|
||||
break;
|
||||
case R.id.map_list_menu_hybrid:
|
||||
case map_list_menu_hybrid:
|
||||
if (googleMap != null) {
|
||||
googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
|
||||
}
|
||||
break;
|
||||
case R.id.map_to_my_location:
|
||||
case map_to_my_location:
|
||||
if (myLocation != null) {
|
||||
LatLng latLng = new LatLng(myLocation.getLatitude(), myLocation.getLongitude());
|
||||
if (googleMap != null) {
|
||||
|
@ -19,7 +19,6 @@ import android.support.v4.internal.view.SupportMenuItem;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.Display;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
@ -113,9 +112,10 @@ public class LoginActivity extends ActionBarActivity implements SlideView.SlideV
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.group_create_menu, menu);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.findItem(R.id.done_menu_item);
|
||||
SupportMenuItem doneItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, null);
|
||||
doneItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
doneItem.setActionView(R.layout.group_create_done_layout);
|
||||
|
||||
TextView doneTextView = (TextView)doneItem.getActionView().findViewById(R.id.done_button);
|
||||
doneTextView.setText(LocaleController.getString("Done", R.string.Done));
|
||||
doneTextView.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -75,6 +75,12 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
|
||||
public MessagesActivityDelegate delegate;
|
||||
|
||||
private final static int messages_list_menu_new_messages = 1;
|
||||
private final static int messages_list_menu_new_chat = 2;
|
||||
private final static int messages_list_menu_new_secret_chat = 3;
|
||||
private final static int messages_list_menu_contacts = 4;
|
||||
private final static int messages_list_menu_settings = 5;
|
||||
|
||||
public static interface MessagesActivityDelegate {
|
||||
public abstract void didSelectDialog(MessagesActivity fragment, long dialog_id);
|
||||
}
|
||||
@ -434,7 +440,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
private void didSelectResult(final long dialog_id, boolean useAlert) {
|
||||
if (useAlert && selectAlertString != 0) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setTitle(R.string.AppName);
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
int lower_part = (int)dialog_id;
|
||||
if (lower_part != 0) {
|
||||
if (lower_part > 0) {
|
||||
@ -535,13 +541,25 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (onlySelect) {
|
||||
inflater.inflate(R.menu.messages_list_select_menu, menu);
|
||||
} else {
|
||||
inflater.inflate(R.menu.messages_list_menu, menu);
|
||||
searchItem = (SupportMenuItem)menu.add(Menu.NONE, 0, Menu.NONE, LocaleController.getString("Search", R.string.Search)).setIcon(R.drawable.ic_ab_search);
|
||||
searchItem.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS|SupportMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
searchItem.setActionView(searchView = new SearchView(parentActivity));
|
||||
if (!onlySelect) {
|
||||
SupportMenuItem item = (SupportMenuItem)menu.add(Menu.NONE, messages_list_menu_new_messages, Menu.NONE, LocaleController.getString("NewMessages", R.string.NewMessages)).setIcon(R.drawable.ic_ab_compose);
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
item = (SupportMenuItem)menu.add(Menu.NONE, messages_list_menu_new_chat, Menu.NONE, LocaleController.getString("NewGroup", R.string.NewGroup));
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_NEVER);
|
||||
|
||||
item = (SupportMenuItem)menu.add(Menu.NONE, messages_list_menu_new_secret_chat, Menu.NONE, LocaleController.getString("NewSecretChat", R.string.NewSecretChat));
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_NEVER);
|
||||
|
||||
item = (SupportMenuItem)menu.add(Menu.NONE, messages_list_menu_contacts, Menu.NONE, LocaleController.getString("Contacts", R.string.Contacts));
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_NEVER);
|
||||
|
||||
item = (SupportMenuItem)menu.add(Menu.NONE, messages_list_menu_settings, Menu.NONE, LocaleController.getString("Settings", R.string.Settings));
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_NEVER);
|
||||
}
|
||||
searchItem = (SupportMenuItem)menu.findItem(R.id.messages_list_menu_search);
|
||||
searchView = (SearchView) searchItem.getActionView();
|
||||
|
||||
TextView textView = (TextView) searchView.findViewById(R.id.search_src_text);
|
||||
if (textView != null) {
|
||||
@ -634,15 +652,15 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
}
|
||||
switch (itemId) {
|
||||
|
||||
case R.id.messages_list_menu_settings: {
|
||||
case messages_list_menu_settings: {
|
||||
((LaunchActivity)inflaterActivity).presentFragment(new SettingsActivity(), "settings", false);
|
||||
break;
|
||||
}
|
||||
case R.id.messages_list_menu_contacts: {
|
||||
case messages_list_menu_contacts: {
|
||||
((LaunchActivity)inflaterActivity).presentFragment(new ContactsActivity(), "contacts", false);
|
||||
break;
|
||||
}
|
||||
case R.id.messages_list_menu_new_messages: {
|
||||
case messages_list_menu_new_messages: {
|
||||
BaseFragment fragment = new ContactsActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean("onlyUsers", true);
|
||||
@ -653,7 +671,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
((LaunchActivity)inflaterActivity).presentFragment(fragment, "contacts_chat", false);
|
||||
break;
|
||||
}
|
||||
case R.id.messages_list_menu_new_secret_chat: {
|
||||
case messages_list_menu_new_secret_chat: {
|
||||
BaseFragment fragment = new ContactsActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean("onlyUsers", true);
|
||||
@ -665,7 +683,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
|
||||
((LaunchActivity)inflaterActivity).presentFragment(fragment, "contacts_chat", false);
|
||||
break;
|
||||
}
|
||||
case R.id.messages_list_menu_new_chat: {
|
||||
case messages_list_menu_new_chat: {
|
||||
((LaunchActivity)inflaterActivity).presentFragment(new GroupCreateActivity(), "group_create", false);
|
||||
break;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Base64;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
@ -88,6 +90,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
private int audioDownloadSection;
|
||||
private int audioDownloadChatRow;
|
||||
private int audioDownloadPrivateRow;
|
||||
private int telegramFaqRow;
|
||||
private int languageRow;
|
||||
|
||||
@Override
|
||||
@ -178,6 +181,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
clearLogsRow = rowCount++;
|
||||
switchBackendButtonRow = rowCount++;
|
||||
}
|
||||
telegramFaqRow = rowCount++;
|
||||
askQuestionRow = rowCount++;
|
||||
logoutRow = rowCount++;
|
||||
|
||||
@ -241,6 +245,147 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
} else if (i == backgroundRow) {
|
||||
((LaunchActivity)parentActivity).presentFragment(new SettingsWallpapersActivity(), "settings_wallpapers", false);
|
||||
} else if (i == askQuestionRow) {
|
||||
if (parentActivity == null) {
|
||||
return;
|
||||
}
|
||||
final TextView message = new TextView(parentActivity);
|
||||
message.setText(Html.fromHtml(LocaleController.getString("AskAQuestionInfo", R.string.AskAQuestionInfo)));
|
||||
message.setTextSize(18);
|
||||
message.setPadding(Utilities.dp(8), Utilities.dp(5), Utilities.dp(8), Utilities.dp(6));
|
||||
message.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setView(message);
|
||||
builder.setPositiveButton(LocaleController.getString("AskButton", R.string.AskButton), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
performAskAQuestion();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
} else if (i == sendLogsRow) {
|
||||
sendLogs();
|
||||
} else if (i == clearLogsRow) {
|
||||
FileLog.cleanupLogs();
|
||||
} else if (i == sendByEnterRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean send = preferences.getBoolean("send_by_enter", false);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("send_by_enter", !send);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == terminateSessionsRow) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure));
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
TLRPC.TL_auth_resetAuthorizations req = new TLRPC.TL_auth_resetAuthorizations();
|
||||
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
ActionBarActivity inflaterActivity = parentActivity;
|
||||
if (inflaterActivity == null) {
|
||||
inflaterActivity = (ActionBarActivity)getActivity();
|
||||
}
|
||||
if (inflaterActivity == null) {
|
||||
return;
|
||||
}
|
||||
if (error == null && response instanceof TLRPC.TL_boolTrue) {
|
||||
Toast toast = Toast.makeText(inflaterActivity, R.string.TerminateAllSessions, Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
} else {
|
||||
Toast toast = Toast.makeText(inflaterActivity, R.string.UnknownError, Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
UserConfig.registeredForPush = false;
|
||||
MessagesController.getInstance().registerForPush(UserConfig.pushString);
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassGeneric);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
} else if (i == photoDownloadChatRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("photo_download_chat", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("photo_download_chat", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == photoDownloadPrivateRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("photo_download_user", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("photo_download_user", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == audioDownloadChatRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("audio_download_chat", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("audio_download_chat", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == audioDownloadPrivateRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("audio_download_user", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("audio_download_user", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == languageRow) {
|
||||
((LaunchActivity)parentActivity).presentFragment(new LanguageSelectActivity(), "settings_lang", false);
|
||||
} else if (i == switchBackendButtonRow) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure));
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
ConnectionsManager.getInstance().switchBackend();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
} else if (i == telegramFaqRow) {
|
||||
try {
|
||||
Intent pickIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)));
|
||||
parentActivity.startActivity(pickIntent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
listView.setOnTouchListener(new OnSwipeTouchListener() {
|
||||
public void onSwipeRight() {
|
||||
finishFragment(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ViewGroup parent = (ViewGroup)fragmentView.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(fragmentView);
|
||||
}
|
||||
}
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
public void performAskAQuestion() {
|
||||
final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
int uid = preferences.getInt("support_id", 0);
|
||||
TLRPC.User supportUser = null;
|
||||
@ -326,130 +471,27 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
fragment.setArguments(bundle);
|
||||
((LaunchActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
|
||||
}
|
||||
} else if (i == sendLogsRow) {
|
||||
sendLogs();
|
||||
} else if (i == clearLogsRow) {
|
||||
FileLog.cleanupLogs();
|
||||
} else if (i == sendByEnterRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean send = preferences.getBoolean("send_by_enter", false);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("send_by_enter", !send);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == terminateSessionsRow) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure));
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
TLRPC.TL_auth_resetAuthorizations req = new TLRPC.TL_auth_resetAuthorizations();
|
||||
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
ActionBarActivity inflaterActivity = parentActivity;
|
||||
if (inflaterActivity == null) {
|
||||
inflaterActivity = (ActionBarActivity)getActivity();
|
||||
}
|
||||
if (inflaterActivity == null) {
|
||||
return;
|
||||
}
|
||||
if (error == null && response instanceof TLRPC.TL_boolTrue) {
|
||||
Toast toast = Toast.makeText(inflaterActivity, R.string.TerminateAllSessions, Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
} else {
|
||||
Toast toast = Toast.makeText(inflaterActivity, R.string.UnknownError, Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
UserConfig.registeredForPush = false;
|
||||
MessagesController.getInstance().registerForPush(UserConfig.pushString);
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassGeneric);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
} else if (i == photoDownloadChatRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("photo_download_chat", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("photo_download_chat", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == photoDownloadPrivateRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("photo_download_user", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("photo_download_user", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == audioDownloadChatRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("audio_download_chat", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("audio_download_chat", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == audioDownloadPrivateRow) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
boolean value = preferences.getBoolean("audio_download_user", true);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("audio_download_user", !value);
|
||||
editor.commit();
|
||||
if (listView != null) {
|
||||
listView.invalidateViews();
|
||||
}
|
||||
} else if (i == languageRow) {
|
||||
((LaunchActivity)parentActivity).presentFragment(new LanguageSelectActivity(), "settings_wallpapers", false);
|
||||
} else if (i == switchBackendButtonRow) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
|
||||
builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure));
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
ConnectionsManager.getInstance().switchBackend();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show().setCanceledOnTouchOutside(true);
|
||||
}
|
||||
// else if (i == 6) {
|
||||
// UserConfig.saveIncomingPhotos = !UserConfig.saveIncomingPhotos;
|
||||
// listView.invalidateViews();
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
listView.setOnTouchListener(new OnSwipeTouchListener() {
|
||||
public void onSwipeRight() {
|
||||
finishFragment(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ViewGroup parent = (ViewGroup)fragmentView.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(fragmentView);
|
||||
}
|
||||
}
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
avatarUpdater.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSelfArgs(Bundle args) {
|
||||
if (avatarUpdater != null && avatarUpdater.currentPicturePath != null) {
|
||||
args.putString("path", avatarUpdater.currentPicturePath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSelfArgs(Bundle args) {
|
||||
if (avatarUpdater != null) {
|
||||
avatarUpdater.currentPicturePath = args.getString("path");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didReceivedNotification(int id, Object... args) {
|
||||
if (id == MessagesController.updateInterfaces) {
|
||||
@ -557,7 +599,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
return i == textSizeRow || i == enableAnimationsRow || i == blockedRow || i == notificationRow || i == backgroundRow ||
|
||||
i == askQuestionRow || i == sendLogsRow || i == sendByEnterRow || i == terminateSessionsRow || i == photoDownloadPrivateRow ||
|
||||
i == photoDownloadChatRow || i == clearLogsRow || i == audioDownloadChatRow || i == audioDownloadPrivateRow || i == languageRow ||
|
||||
i == switchBackendButtonRow;
|
||||
i == switchBackendButtonRow || i == telegramFaqRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -766,6 +808,9 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
} else if (i == switchBackendButtonRow) {
|
||||
textView.setText("Switch Backend");
|
||||
divider.setVisibility(View.VISIBLE);
|
||||
} else if (i == telegramFaqRow) {
|
||||
textView.setText(LocaleController.getString("TelegramFAQ", R.string.TelegramFaq));
|
||||
divider.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else if (type == 3) {
|
||||
if (view == null) {
|
||||
@ -901,7 +946,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
|
||||
return 5;
|
||||
} else if (i == enableAnimationsRow || i == sendByEnterRow || i == photoDownloadChatRow || i == photoDownloadPrivateRow || i == audioDownloadChatRow || i == audioDownloadPrivateRow) {
|
||||
return 3;
|
||||
} else if (i == numberRow || i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow || i == clearLogsRow || i == switchBackendButtonRow) {
|
||||
} else if (i == numberRow || i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow) {
|
||||
return 2;
|
||||
} else if (i == logoutRow) {
|
||||
return 4;
|
||||
|
@ -12,6 +12,7 @@ import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.internal.view.SupportMenuItem;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@ -37,7 +38,6 @@ import org.telegram.messenger.Utilities;
|
||||
import org.telegram.ui.Cells.ChatOrUserCell;
|
||||
import org.telegram.ui.Views.BaseFragment;
|
||||
import org.telegram.ui.Views.OnSwipeTouchListener;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -52,6 +52,8 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe
|
||||
private HashMap<Integer, TLRPC.TL_contactBlocked> blockedContactsDict = new HashMap<Integer, TLRPC.TL_contactBlocked>();
|
||||
private int selectedUserId;
|
||||
|
||||
private final static int block_user = 1;
|
||||
|
||||
@Override
|
||||
public boolean onFragmentCreate() {
|
||||
super.onFragmentCreate();
|
||||
@ -293,7 +295,8 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe
|
||||
}
|
||||
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.settings_block_users_bar_menu, menu);
|
||||
SupportMenuItem item = (SupportMenuItem)menu.add(Menu.NONE, block_user, Menu.NONE, null).setIcon(R.drawable.plus);
|
||||
item.setShowAsAction(SupportMenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -303,7 +306,7 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe
|
||||
case android.R.id.home:
|
||||
finishFragment();
|
||||
break;
|
||||
case R.id.block_user:
|
||||
case block_user:
|
||||
ContactsActivity fragment = new ContactsActivity();
|
||||
fragment.animationType = 1;
|
||||
Bundle bundle = new Bundle();
|
||||
|
@ -103,6 +103,9 @@ public class SettingsNotificationsActivity extends BaseFragment {
|
||||
editor.commit();
|
||||
listView.invalidateViews();
|
||||
} else if (i == 4 || i == 9) {
|
||||
if (parentActivity == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||
Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||
@ -137,7 +140,7 @@ public class SettingsNotificationsActivity extends BaseFragment {
|
||||
}
|
||||
}
|
||||
tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound);
|
||||
startActivityForResult(tmpIntent, i);
|
||||
parentActivity.startActivityForResult(tmpIntent, i);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -228,8 +231,7 @@ public class SettingsNotificationsActivity extends BaseFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
||||
String name = null;
|
||||
|
@ -15,7 +15,6 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@ -80,6 +79,8 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
selectedBackground = preferences.getInt("selectedBackground", 1000001);
|
||||
selectedColor = preferences.getInt("selectedColor", 0);
|
||||
MessagesStorage.getInstance().getWallpapers();
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg");
|
||||
toFile.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -113,6 +114,9 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
builder.setItems(items, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (parentActivity == null) {
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
File image = Utilities.generatePicturePath();
|
||||
@ -120,11 +124,11 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
|
||||
currentPicturePath = image.getAbsolutePath();
|
||||
}
|
||||
startActivityForResult(takePictureIntent, 0);
|
||||
parentActivity.startActivityForResult(takePictureIntent, 10);
|
||||
} else if (i == 1) {
|
||||
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
|
||||
photoPickerIntent.setType("image/*");
|
||||
startActivityForResult(photoPickerIntent, 1);
|
||||
parentActivity.startActivityForResult(photoPickerIntent, 11);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -167,9 +171,15 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
done = false;
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
} else {
|
||||
if (selectedBackground == -1) {
|
||||
File fromFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg");
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg");
|
||||
done = fromFile.renameTo(toFile);
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||
@ -194,14 +204,13 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == 0) {
|
||||
if (requestCode == 10) {
|
||||
Utilities.addMediaToGallery(currentPicturePath);
|
||||
try {
|
||||
Bitmap bitmap = FileLoader.loadBitmap(currentPicturePath, null, Utilities.dp(320), Utilities.dp(480));
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg");
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg");
|
||||
FileOutputStream stream = new FileOutputStream(toFile);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream);
|
||||
selectedBackground = -1;
|
||||
@ -211,22 +220,13 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
currentPicturePath = null;
|
||||
} else if (requestCode == 1) {
|
||||
Uri imageUri = data.getData();
|
||||
Cursor cursor = parentActivity.getContentResolver().query(imageUri, new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null);
|
||||
if (cursor == null) {
|
||||
} else if (requestCode == 11) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String imageFilePath = null;
|
||||
if (cursor.moveToFirst()) {
|
||||
imageFilePath = cursor.getString(0);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
Bitmap bitmap = FileLoader.loadBitmap(imageFilePath, null, Utilities.dp(320), Utilities.dp(480));
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg");
|
||||
Bitmap bitmap = FileLoader.loadBitmap(null, data.getData(), Utilities.dp(320), Utilities.dp(480));
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg");
|
||||
FileOutputStream stream = new FileOutputStream(toFile);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream);
|
||||
selectedBackground = -1;
|
||||
@ -239,6 +239,18 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSelfArgs(Bundle args) {
|
||||
if (currentPicturePath != null) {
|
||||
args.putString("path", currentPicturePath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSelfArgs(Bundle args) {
|
||||
currentPicturePath = args.getString("path");
|
||||
}
|
||||
|
||||
private void processSelectedBackground() {
|
||||
TLRPC.WallPaper wallPaper = wallpappersByIds.get(selectedBackground);
|
||||
if (selectedBackground != -1 && selectedBackground != 1000001 && wallPaper != null && wallPaper instanceof TLRPC.TL_wallPaper) {
|
||||
@ -277,7 +289,10 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
|
||||
backgroundImage.setBackgroundColor(0);
|
||||
selectedColor = 0;
|
||||
} else if (selectedBackground == -1) {
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg");
|
||||
File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg");
|
||||
if (!toFile.exists()) {
|
||||
toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg");
|
||||
}
|
||||
if (toFile.exists()) {
|
||||
backgroundImage.setImageURI(Uri.fromFile(toFile));
|
||||
} else {
|
||||
|
@ -66,6 +66,12 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
private long dialog_id;
|
||||
private TLRPC.EncryptedChat currentEncryptedChat;
|
||||
|
||||
private final static int add_contact = 1;
|
||||
private final static int block_contact = 2;
|
||||
private final static int share_contact = 3;
|
||||
private final static int edit_contact = 4;
|
||||
private final static int delete_contact = 5;
|
||||
|
||||
@Override
|
||||
public boolean onFragmentCreate() {
|
||||
super.onFragmentCreate();
|
||||
@ -144,6 +150,9 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
} else if (i == 5 && dialog_id == 0 ||
|
||||
dialog_id != 0 && (i == 7 && currentEncryptedChat instanceof TLRPC.TL_encryptedChat ||
|
||||
i == 5 && !(currentEncryptedChat instanceof TLRPC.TL_encryptedChat))) {
|
||||
if (parentActivity == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Intent tmpIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||
tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
|
||||
@ -168,7 +177,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
}
|
||||
|
||||
tmpIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentSound);
|
||||
startActivityForResult(tmpIntent, 0);
|
||||
parentActivity.startActivityForResult(tmpIntent, 12);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -256,8 +265,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (data == null) {
|
||||
return;
|
||||
@ -279,7 +287,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
|
||||
if (requestCode == 0) {
|
||||
if (requestCode == 12) {
|
||||
if (name != null && ringtone != null) {
|
||||
editor.putString("sound_" + user_id, name);
|
||||
editor.putString("sound_path_" + user_id, ringtone.toString());
|
||||
@ -424,7 +432,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
case android.R.id.home:
|
||||
finishFragment();
|
||||
break;
|
||||
case R.id.block_contact: {
|
||||
case block_contact: {
|
||||
TLRPC.User user = MessagesController.getInstance().users.get(user_id);
|
||||
if (user == null) {
|
||||
break;
|
||||
@ -442,7 +450,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
}, null, true, RPCRequest.RPCRequestClassGeneric);
|
||||
break;
|
||||
}
|
||||
case R.id.add_contact: {
|
||||
case add_contact: {
|
||||
TLRPC.User user = MessagesController.getInstance().users.get(user_id);
|
||||
ContactAddActivity fragment = new ContactAddActivity();
|
||||
Bundle args = new Bundle();
|
||||
@ -451,7 +459,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
((LaunchActivity)parentActivity).presentFragment(fragment, "add_contact_" + user.id, false);
|
||||
break;
|
||||
}
|
||||
case R.id.share_contact: {
|
||||
case share_contact: {
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("onlySelect", true);
|
||||
@ -461,7 +469,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
((LaunchActivity)parentActivity).presentFragment(fragment, "chat_select", false);
|
||||
break;
|
||||
}
|
||||
case R.id.edit_contact: {
|
||||
case edit_contact: {
|
||||
ContactAddActivity fragment = new ContactAddActivity();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("user_id", user_id);
|
||||
@ -469,7 +477,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
((LaunchActivity)parentActivity).presentFragment(fragment, "add_contact_" + user_id, false);
|
||||
break;
|
||||
}
|
||||
case R.id.delete_contact: {
|
||||
case delete_contact: {
|
||||
final TLRPC.User user = MessagesController.getInstance().users.get(user_id);
|
||||
if (user == null) {
|
||||
break;
|
||||
@ -501,12 +509,16 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
|
||||
return;
|
||||
}
|
||||
if (user.phone != null && user.phone.length() != 0) {
|
||||
inflater.inflate(R.menu.user_profile_menu, menu);
|
||||
menu.add(Menu.NONE, add_contact, Menu.NONE, LocaleController.getString("AddContact", R.string.AddContact));
|
||||
menu.add(Menu.NONE, block_contact, Menu.NONE, LocaleController.getString("BlockContact", R.string.BlockContact));
|
||||
} else {
|
||||
inflater.inflate(R.menu.user_profile_block_menu, menu);
|
||||
menu.add(Menu.NONE, block_contact, Menu.NONE, LocaleController.getString("BlockContact", R.string.BlockContact));
|
||||
}
|
||||
} else {
|
||||
inflater.inflate(R.menu.user_profile_contact_menu, menu);
|
||||
menu.add(Menu.NONE, share_contact, Menu.NONE, LocaleController.getString("ShareContact", R.string.ShareContact));
|
||||
menu.add(Menu.NONE, block_contact, Menu.NONE, LocaleController.getString("BlockContact", R.string.BlockContact));
|
||||
menu.add(Menu.NONE, edit_contact, Menu.NONE, LocaleController.getString("EditContact", R.string.EditContact));
|
||||
menu.add(Menu.NONE, delete_contact, Menu.NONE, LocaleController.getString("DeleteContact", R.string.DeleteContact));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
|
||||
currentPicturePath = image.getAbsolutePath();
|
||||
}
|
||||
parentFragment.startActivityForResult(takePictureIntent, 0);
|
||||
parentFragment.parentActivity.startActivityForResult(takePictureIntent, 13);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -68,7 +68,7 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg
|
||||
try {
|
||||
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
|
||||
photoPickerIntent.setType("image/*");
|
||||
parentFragment.startActivityForResult(photoPickerIntent, 1);
|
||||
parentFragment.parentActivity.startActivityForResult(photoPickerIntent, 14);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -102,12 +102,12 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == 0) {
|
||||
if (requestCode == 13) {
|
||||
Utilities.addMediaToGallery(currentPicturePath);
|
||||
startCrop(currentPicturePath, null);
|
||||
|
||||
currentPicturePath = null;
|
||||
} else if (requestCode == 1) {
|
||||
} else if (requestCode == 14) {
|
||||
if (data == null || data.getData() == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -176,6 +176,12 @@ public class BackupImageView extends ImageView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
recycleBitmap(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
try {
|
||||
@ -188,12 +194,6 @@ public class BackupImageView extends ImageView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
recycleBitmap(null);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void setImageResourceMy(int resId) {
|
||||
if (ignoreLayout) {
|
||||
makeRequest = false;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package org.telegram.ui.Views;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
@ -28,6 +29,7 @@ public class BaseFragment extends Fragment {
|
||||
public int classGuid = 0;
|
||||
public boolean firstStart = true;
|
||||
public boolean animationInProgress = false;
|
||||
private long currentAnimationDuration = 0;
|
||||
private boolean removeParentOnDestroy = false;
|
||||
private boolean removeParentOnAnimationEnd = true;
|
||||
|
||||
@ -108,6 +110,16 @@ public class BaseFragment extends Fragment {
|
||||
|
||||
public void onAnimationStart() {
|
||||
animationInProgress = true;
|
||||
if (fragmentView != null) {
|
||||
fragmentView.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (animationInProgress) {
|
||||
onAnimationEnd();
|
||||
}
|
||||
}
|
||||
}, currentAnimationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
public void onAnimationEnd() {
|
||||
@ -137,6 +149,7 @@ public class BaseFragment extends Fragment {
|
||||
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
|
||||
if (nextAnim != 0) {
|
||||
Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
|
||||
currentAnimationDuration = anim.getDuration();
|
||||
|
||||
anim.setAnimationListener(new Animation.AnimationListener() {
|
||||
|
||||
@ -149,8 +162,10 @@ public class BaseFragment extends Fragment {
|
||||
}
|
||||
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
if (animationInProgress) {
|
||||
BaseFragment.this.onAnimationEnd();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return anim;
|
||||
@ -166,4 +181,16 @@ public class BaseFragment extends Fragment {
|
||||
public void applySelfActionBar() {
|
||||
|
||||
}
|
||||
|
||||
public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
|
||||
|
||||
}
|
||||
|
||||
public void saveSelfArgs(Bundle args) {
|
||||
|
||||
}
|
||||
|
||||
public void restoreSelfArgs(Bundle args) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,407 @@
|
||||
/*
|
||||
https://github.com/koral--/android-gif-drawable/
|
||||
MIT License
|
||||
Copyright (c)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.telegram.ui.Views;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.widget.MediaController;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GifDrawable extends Drawable implements Animatable, MediaController.MediaPlayerControl {
|
||||
|
||||
private static native void renderFrame(int[] pixels, int gifFileInPtr, int[] metaData);
|
||||
private static native int openFile(int[] metaData, String filePath);
|
||||
private static native void free(int gifFileInPtr);
|
||||
private static native boolean reset(int gifFileInPtr);
|
||||
private static native void setSpeedFactor(int gifFileInPtr, float factor);
|
||||
private static native String getComment(int gifFileInPtr);
|
||||
private static native int getLoopCount(int gifFileInPtr);
|
||||
private static native int getDuration(int gifFileInPtr);
|
||||
private static native int getCurrentPosition(int gifFileInPtr);
|
||||
private static native int seekToTime(int gifFileInPtr, int pos, int[] pixels);
|
||||
private static native int seekToFrame(int gifFileInPtr, int frameNr, int[] pixels);
|
||||
private static native int saveRemainder(int gifFileInPtr);
|
||||
private static native int restoreRemainder(int gifFileInPtr);
|
||||
private static native long getAllocationByteCount(int gifFileInPtr);
|
||||
|
||||
private static final Handler UI_HANDLER = new Handler(Looper.getMainLooper());
|
||||
|
||||
private volatile int mGifInfoPtr;
|
||||
private volatile boolean mIsRunning = true;
|
||||
|
||||
private final int[] mMetaData = new int[5];//[w, h, imageCount, errorCode, post invalidation time]
|
||||
private final long mInputSourceLength;
|
||||
|
||||
private float mSx = 1f;
|
||||
private float mSy = 1f;
|
||||
private boolean mApplyTransformation;
|
||||
private final Rect mDstRect = new Rect();
|
||||
|
||||
public WeakReference<View> parentView = null;
|
||||
|
||||
protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
|
||||
protected final int[] mColors;
|
||||
|
||||
private final Runnable mResetTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reset(mGifInfoPtr);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mStartTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
restoreRemainder(mGifInfoPtr);
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
mMetaData[4] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mSaveRemainderTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
saveRemainder(mGifInfoPtr);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mInvalidateTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static void runOnUiThread(Runnable task) {
|
||||
if (Looper.myLooper() == UI_HANDLER.getLooper()) {
|
||||
task.run();
|
||||
} else {
|
||||
UI_HANDLER.post(task);
|
||||
}
|
||||
}
|
||||
|
||||
public GifDrawable(String filePath) throws Exception {
|
||||
mInputSourceLength = new File(filePath).length();
|
||||
mGifInfoPtr = openFile(mMetaData, filePath);
|
||||
mColors = new int[mMetaData[0] * mMetaData[1]];
|
||||
}
|
||||
|
||||
public GifDrawable(File file) throws Exception {
|
||||
mInputSourceLength = file.length();
|
||||
mGifInfoPtr = openFile(mMetaData, file.getPath());
|
||||
mColors = new int[mMetaData[0] * mMetaData[1]];
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
mIsRunning = false;
|
||||
int tmpPtr = mGifInfoPtr;
|
||||
mGifInfoPtr = 0;
|
||||
free(tmpPtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
recycle();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mMetaData[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mMetaData[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mPaint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mPaint.setColorFilter(cf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSPARENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (mIsRunning) {
|
||||
return;
|
||||
}
|
||||
mIsRunning = true;
|
||||
runOnUiThread(mStartTask);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
runOnUiThread(mResetTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
mIsRunning = false;
|
||||
runOnUiThread(mSaveRemainderTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return getComment(mGifInfoPtr);
|
||||
}
|
||||
|
||||
public int getLoopCount() {
|
||||
return getLoopCount(mGifInfoPtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "Size: %dx%d, %d frames, error: %d", mMetaData[0], mMetaData[1], mMetaData[2], mMetaData[3]);
|
||||
}
|
||||
|
||||
public int getNumberOfFrames() {
|
||||
return mMetaData[2];
|
||||
}
|
||||
|
||||
public int getError() {
|
||||
return mMetaData[3];
|
||||
}
|
||||
|
||||
public void setSpeed(float factor) {
|
||||
if (factor <= 0f) {
|
||||
throw new IllegalArgumentException("Speed factor is not positive");
|
||||
}
|
||||
setSpeedFactor(mGifInfoPtr, factor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDuration() {
|
||||
return getDuration(mGifInfoPtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentPosition() {
|
||||
return getCurrentPosition(mGifInfoPtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekTo(final int position) {
|
||||
if (position < 0) {
|
||||
throw new IllegalArgumentException("Position is not positive");
|
||||
}
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
seekToTime(mGifInfoPtr, position, mColors);
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void seekToFrame(final int frameIndex) {
|
||||
if (frameIndex < 0) {
|
||||
throw new IllegalArgumentException("frameIndex is not positive");
|
||||
}
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
seekToFrame(mGifInfoPtr, frameIndex, mColors);
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlaying() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferPercentage() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekBackward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekForward() {
|
||||
return getNumberOfFrames() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAudioSessionId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getFrameByteCount() {
|
||||
return mMetaData[0] * mMetaData[1] * 4;
|
||||
}
|
||||
|
||||
public long getAllocationByteCount() {
|
||||
return getAllocationByteCount(mGifInfoPtr) + mColors.length * 4L;
|
||||
}
|
||||
|
||||
public long getInputSourceByteCount() {
|
||||
return mInputSourceLength;
|
||||
}
|
||||
|
||||
public void getPixels(int[] pixels) {
|
||||
if (pixels.length < mColors.length) {
|
||||
throw new ArrayIndexOutOfBoundsException("Pixels array is too small. Required length: " + mColors.length);
|
||||
}
|
||||
System.arraycopy(mColors, 0, pixels, 0, mColors.length);
|
||||
}
|
||||
|
||||
public int getPixel(int x, int y) {
|
||||
if (x < 0) {
|
||||
throw new IllegalArgumentException("x must be >= 0");
|
||||
}
|
||||
if (y < 0) {
|
||||
throw new IllegalArgumentException("y must be >= 0");
|
||||
}
|
||||
if (x >= mMetaData[0]) {
|
||||
throw new IllegalArgumentException("x must be < GIF width");
|
||||
}
|
||||
if (y >= mMetaData[1]) {
|
||||
throw new IllegalArgumentException("y must be < GIF height");
|
||||
}
|
||||
return mColors[mMetaData[1] * y + x];
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
seekToFrame(mGifInfoPtr, 0, mColors);
|
||||
return Bitmap.createBitmap(mColors, 0, mMetaData[0], mMetaData[0], mMetaData[1], Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mApplyTransformation = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (mApplyTransformation) {
|
||||
mDstRect.set(getBounds());
|
||||
mSx = (float) mDstRect.width() / mMetaData[0];
|
||||
mSy = (float) mDstRect.height() / mMetaData[1];
|
||||
mApplyTransformation = false;
|
||||
}
|
||||
if (mPaint.getShader() == null) {
|
||||
if (mIsRunning) {
|
||||
renderFrame(mColors, mGifInfoPtr, mMetaData);
|
||||
} else {
|
||||
mMetaData[4] = -1;
|
||||
}
|
||||
canvas.translate(mDstRect.left, mDstRect.top);
|
||||
canvas.scale(mSx, mSy);
|
||||
canvas.drawBitmap(mColors, 0, mMetaData[0], 0f, 0f, mMetaData[0], mMetaData[1], true, mPaint);
|
||||
if (mMetaData[4] >= 0 && mMetaData[2] > 1) {
|
||||
UI_HANDLER.postDelayed(mInvalidateTask, mMetaData[4]);
|
||||
}
|
||||
} else {
|
||||
canvas.drawRect(mDstRect, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
public final Paint getPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlpha() {
|
||||
return mPaint.getAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilterBitmap(boolean filter) {
|
||||
mPaint.setFilterBitmap(filter);
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDither(boolean dither) {
|
||||
mPaint.setDither(dither);
|
||||
if (parentView != null && parentView.get() != null) {
|
||||
parentView.get().invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumHeight() {
|
||||
return mMetaData[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumWidth() {
|
||||
return mMetaData[0];
|
||||
}
|
||||
}
|
@ -111,6 +111,34 @@ public class ImageReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageBitmap(Bitmap bitmap) {
|
||||
currentPath = null;
|
||||
last_path = null;
|
||||
last_httpUrl = null;
|
||||
last_filter = null;
|
||||
last_placeholder = null;
|
||||
last_size = 0;
|
||||
FileLoader.getInstance().cancelLoadingForImageView(this);
|
||||
if (bitmap != null) {
|
||||
recycleBitmap(null);
|
||||
currentImage = new BitmapDrawable(null, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageBitmap(Drawable bitmap) {
|
||||
currentPath = null;
|
||||
last_path = null;
|
||||
last_httpUrl = null;
|
||||
last_filter = null;
|
||||
last_placeholder = null;
|
||||
last_size = 0;
|
||||
FileLoader.getInstance().cancelLoadingForImageView(this);
|
||||
if (bitmap != null) {
|
||||
recycleBitmap(null);
|
||||
currentImage = bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearImage() {
|
||||
recycleBitmap(null);
|
||||
}
|
||||
@ -137,6 +165,7 @@ public class ImageReceiver {
|
||||
} else {
|
||||
currentImage = null;
|
||||
}
|
||||
currentPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,10 +189,4 @@ public class ImageReceiver {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
recycleBitmap(null);
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
@ -14,50 +14,35 @@ import android.graphics.Paint;
|
||||
import org.telegram.messenger.Utilities;
|
||||
|
||||
public class ProgressView {
|
||||
private static Paint innerPaint1;
|
||||
private static Paint outerPaint1;
|
||||
private static Paint innerPaint2;
|
||||
private static Paint outerPaint2;
|
||||
private Paint innerPaint;
|
||||
private Paint outerPaint;
|
||||
|
||||
public int type;
|
||||
public int thumbX = 0;
|
||||
public float currentProgress = 0;
|
||||
public int width;
|
||||
public int height;
|
||||
public float progressHeight = Utilities.dpf(2.0f);
|
||||
|
||||
public ProgressView() {
|
||||
if (innerPaint1 == null) {
|
||||
innerPaint1 = new Paint();
|
||||
outerPaint1 = new Paint();
|
||||
innerPaint2 = new Paint();
|
||||
outerPaint2 = new Paint();
|
||||
|
||||
innerPaint1.setColor(0xffb4e396);
|
||||
outerPaint1.setColor(0xff6ac453);
|
||||
innerPaint2.setColor(0xffd9e2eb);
|
||||
outerPaint2.setColor(0xff86c5f8);
|
||||
innerPaint = new Paint();
|
||||
outerPaint = new Paint();
|
||||
}
|
||||
|
||||
public void setProgressColors(int innerColor, int outerColor) {
|
||||
innerPaint.setColor(innerColor);
|
||||
outerPaint.setColor(outerColor);
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
thumbX = (int)Math.ceil(width * progress);
|
||||
if (thumbX < 0) {
|
||||
thumbX = 0;
|
||||
} else if (thumbX > width) {
|
||||
thumbX = width;
|
||||
currentProgress = progress;
|
||||
if (currentProgress < 0) {
|
||||
currentProgress = 0;
|
||||
} else if (currentProgress > 1) {
|
||||
currentProgress = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
Paint inner = null;
|
||||
Paint outer = null;
|
||||
if (type == 0) {
|
||||
inner = innerPaint1;
|
||||
outer = outerPaint1;
|
||||
} else if (type == 1) {
|
||||
inner = innerPaint2;
|
||||
outer = outerPaint2;
|
||||
}
|
||||
canvas.drawRect(0, height / 2 - Utilities.dp(1), width, height / 2 + Utilities.dp(1), inner);
|
||||
canvas.drawRect(0, height / 2 - Utilities.dp(1), thumbX, height / 2 + Utilities.dp(1), outer);
|
||||
canvas.drawRect(0, height / 2 - progressHeight / 2.0f, width, height / 2 + progressHeight / 2.0f, innerPaint);
|
||||
canvas.drawRect(0, height / 2 - progressHeight / 2.0f, width * currentProgress, height / 2 + progressHeight / 2.0f, outerPaint);
|
||||
}
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="1dp"
|
||||
android:paddingTop="1dp"
|
||||
android:layout_gravity="top">
|
||||
|
||||
<org.telegram.ui.Views.BackupImageView
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:id="@+id/chat_group_avatar_image"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_gravity="bottom"/>
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="13dp"
|
||||
android:layout_gravity="top"
|
||||
android:id="@+id/chat_bubble_layout"
|
||||
android:addStatesFromChildren="true">
|
||||
|
||||
<org.telegram.ui.Views.BackupImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_margin="6dp"
|
||||
android:layout_gravity="top"
|
||||
android:scaleType="centerCrop"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:id="@+id/chat_photo_image"/>
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_height="44dp"
|
||||
android:layout_width="44dp"
|
||||
android:id="@+id/chat_view_action_layout"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:scaleType="centerInside"
|
||||
android:id="@+id/chat_view_action_cancel_button"
|
||||
android:src="@drawable/photo_download_states"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:gravity="right">
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="1dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="@drawable/phototime"
|
||||
android:id="@+id/photo_progress"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="3dp"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:progressDrawable="@drawable/photo_progress_chat"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:progress="50"
|
||||
android:id="@+id/chat_view_action_progress"
|
||||
android:max="100"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:id="@+id/chat_time_layout"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingRight="3dp"
|
||||
android:background="@drawable/phototime">
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="12dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:id="@+id/chat_time_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
</LinearLayout>
|
@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="1dp"
|
||||
android:paddingTop="1dp"
|
||||
android:layout_gravity="top">
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="9dp"
|
||||
android:id="@+id/chat_bubble_layout"
|
||||
android:layout_gravity="top"
|
||||
android:addStatesFromChildren="true">
|
||||
|
||||
<org.telegram.ui.Views.BackupImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_margin="6dp"
|
||||
android:layout_gravity="top"
|
||||
android:scaleType="centerCrop"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:id="@+id/chat_photo_image"/>
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_height="44dp"
|
||||
android:layout_width="44dp"
|
||||
android:id="@+id/chat_view_action_layout"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:scaleType="centerInside"
|
||||
android:id="@+id/chat_view_action_cancel_button"
|
||||
android:src="@drawable/photo_download_states"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:gravity="right">
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="1dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="@drawable/phototime"
|
||||
android:id="@+id/photo_progress"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="3dp"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:progressDrawable="@drawable/photo_progress_chat"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:progress="50"
|
||||
android:id="@+id/chat_view_action_progress"
|
||||
android:max="100"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:id="@+id/chat_time_layout"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingRight="3dp"
|
||||
android:background="@drawable/phototime">
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="12dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:id="@+id/chat_time_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
</LinearLayout>
|
@ -151,7 +151,7 @@
|
||||
android:layout_marginTop="2dp"
|
||||
android:maxLines="4"
|
||||
android:minHeight="48dp"
|
||||
android:textSize="18sp"
|
||||
android:textSize="18dp"
|
||||
android:textColorHint="#909090"
|
||||
android:ems="10"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
|
@ -1,123 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:paddingBottom="1dp"
|
||||
android:paddingTop="1dp">
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="9dp"
|
||||
android:id="@+id/chat_bubble_layout"
|
||||
android:addStatesFromChildren="true">
|
||||
|
||||
<org.telegram.ui.Views.BackupImageView
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="100dp"
|
||||
android:layout_margin="6dp"
|
||||
android:layout_gravity="top|left"
|
||||
android:scaleType="centerCrop"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:id="@+id/chat_photo_image"/>
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_height="44dp"
|
||||
android:layout_width="44dp"
|
||||
android:id="@+id/chat_view_action_layout"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:scaleType="centerInside"
|
||||
android:id="@+id/chat_view_action_cancel_button"
|
||||
android:src="@drawable/photo_download_cancel_states"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:gravity="right">
|
||||
|
||||
<org.telegram.ui.Views.FrameLayoutFixed
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="1dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="@drawable/phototime"
|
||||
android:id="@+id/photo_progress"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="3dp"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:progressDrawable="@drawable/photo_progress_chat"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:progress="50"
|
||||
android:id="@+id/chat_view_action_progress"
|
||||
android:max="100"/>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:id="@+id/chat_time_layout"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingRight="3dp"
|
||||
android:background="@drawable/phototime">
|
||||
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="12dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:id="@+id/chat_time_text"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/msg_check_w"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginRight="-8dp"
|
||||
android:id="@+id/chat_row_check"
|
||||
android:visibility="visible"
|
||||
android:layout_gravity="top"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:id="@+id/chat_row_halfcheck"
|
||||
android:visibility="visible"
|
||||
android:src="@drawable/msg_halfcheck_w"
|
||||
android:layout_gravity="top"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.telegram.ui.Views.FrameLayoutFixed>
|
||||
|
||||
</LinearLayout>
|
@ -1,50 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_enc_timer"
|
||||
sabd:showAsAction="always"
|
||||
sabd:actionLayout="@layout/chat_header_enc_layout"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_menu_attach"
|
||||
android:icon="@drawable/ic_ab_attach"
|
||||
android:title="@string/Attach"
|
||||
sabd:showAsAction="always">
|
||||
|
||||
<menu>
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_photo"
|
||||
android:title="@string/ChatTakePhoto"
|
||||
android:id="@+id/attach_photo"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_gallery"
|
||||
android:title="@string/ChatGallery"
|
||||
android:id="@+id/attach_gallery"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_video"
|
||||
android:title="@string/ChatVideo"
|
||||
android:id="@+id/attach_video"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_ab_doc"
|
||||
android:title="@string/ChatDocument"
|
||||
android:id="@+id/attach_document"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_location"
|
||||
android:title="@string/ChatLocation"
|
||||
android:id="@+id/attach_location"/>
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_menu_avatar"
|
||||
sabd:showAsAction="always"
|
||||
sabd:actionLayout="@layout/chat_header_layout"/>
|
||||
|
||||
</menu>
|
@ -1,45 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_menu_attach"
|
||||
android:icon="@drawable/ic_ab_attach"
|
||||
android:title="@string/Attach"
|
||||
sabd:showAsAction="always">
|
||||
|
||||
<menu>
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_photo"
|
||||
android:title="@string/ChatTakePhoto"
|
||||
android:id="@+id/attach_photo"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_gallery"
|
||||
android:title="@string/ChatGallery"
|
||||
android:id="@+id/attach_gallery"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_video"
|
||||
android:title="@string/ChatVideo"
|
||||
android:id="@+id/attach_video"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_ab_doc"
|
||||
android:title="@string/ChatDocument"
|
||||
android:id="@+id/attach_document"/>
|
||||
|
||||
<item
|
||||
android:icon="@drawable/ic_attach_location"
|
||||
android:title="@string/ChatLocation"
|
||||
android:id="@+id/attach_location"/>
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_menu_avatar"
|
||||
sabd:showAsAction="always"
|
||||
sabd:actionLayout="@layout/chat_header_layout"/>
|
||||
|
||||
</menu>
|
@ -1,12 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_search"
|
||||
android:icon="@drawable/ic_ab_search"
|
||||
android:title="@string/Search"
|
||||
sabd:showAsAction="always|collapseActionView"
|
||||
sabd:actionViewClass="android.support.v7.widget.SearchView"/>
|
||||
|
||||
</menu>
|
@ -1,14 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!--<item android:id="@+id/gallery_menu_send"-->
|
||||
<!--android:title="@string/Send"/>-->
|
||||
|
||||
<item
|
||||
android:id="@+id/gallery_menu_save"
|
||||
android:title="@string/SaveToGallery"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/gallery_menu_showall"
|
||||
android:title="@string/ShowAllMedia"/>
|
||||
|
||||
</menu>
|
@ -1,8 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/gallery_menu_save"
|
||||
android:title="@string/SaveToGallery"/>
|
||||
|
||||
</menu>
|
@ -1,10 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/done_menu_item"
|
||||
sabd:showAsAction="always"
|
||||
sabd:actionLayout="@layout/group_create_done_layout"/>
|
||||
|
||||
</menu>
|
@ -1,10 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/block_user"
|
||||
sabd:actionLayout="@layout/group_profile_add_member_layout"
|
||||
sabd:showAsAction="always"/>
|
||||
|
||||
</menu>
|
@ -1,23 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/map_to_my_location"
|
||||
android:icon="@drawable/ic_ab_location"
|
||||
android:title="@string/MyLocation"
|
||||
sabd:showAsAction="always"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/map_list_menu_map"
|
||||
android:title="@string/Map"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/map_list_menu_satellite"
|
||||
android:title="@string/Satellite"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/map_list_menu_hybrid"
|
||||
android:title="@string/Hybrid"/>
|
||||
|
||||
</menu>
|
@ -1,9 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_ab_fwd_delete"
|
||||
android:title="@string/Delete"/>
|
||||
|
||||
</menu>
|
@ -1,14 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/copy"
|
||||
android:icon="@drawable/ic_ab_fwd_copy"
|
||||
android:title="@string/Copy"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_ab_fwd_delete"
|
||||
android:title="@string/Delete"/>
|
||||
|
||||
</menu>
|
@ -1,19 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/copy"
|
||||
android:icon="@drawable/ic_ab_fwd_copy"
|
||||
android:title="@string/Copy"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/forward"
|
||||
android:icon="@drawable/ic_ab_fwd_forward"
|
||||
android:title="@string/Forward"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_ab_fwd_delete"
|
||||
android:title="@string/Delete"/>
|
||||
|
||||
</menu>
|
@ -1,38 +0,0 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sabd="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_search"
|
||||
android:icon="@drawable/ic_ab_search"
|
||||
android:title="@string/Search"
|
||||
sabd:showAsAction="always|collapseActionView"
|
||||
sabd:actionViewClass="android.support.v7.widget.SearchView"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_new_messages"
|
||||
android:icon="@drawable/ic_ab_compose"
|
||||
android:title="@string/NewMessages"
|
||||
sabd:showAsAction="always"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_new_chat"
|
||||
android:title="@string/NewGroup"
|
||||
sabd:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_new_secret_chat"
|
||||
android:title="@string/NewSecretChat"
|
||||
sabd:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_contacts"
|
||||
android:title="@string/Contacts"
|
||||
sabd:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/messages_list_menu_settings"
|
||||
android:title="@string/Settings"
|
||||
sabd:showAsAction="never"/>
|
||||
|
||||
</menu>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user