Merge branch 'dev'

This commit is contained in:
DrKLO 2014-04-03 15:04:00 +04:00
commit 419969f721
111 changed files with 6097 additions and 2421 deletions

View File

@ -82,7 +82,7 @@ android {
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
versionCode 212
versionCode 219
versionName "1.4.9"
}
}

View File

@ -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)

View File

@ -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) {

View File

@ -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
View 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
View 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

View 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

File diff suppressed because it is too large Load Diff

View 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 */

View 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 */

View 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 */

View 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 */

View 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 */

View File

@ -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);

View File

@ -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

View File

@ -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
View 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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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]+");

View File

@ -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;

View File

@ -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;

View File

@ -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.last_name = "";
}
contact.first_name = name;
contact.last_name = "";
contact.id = pCur.getInt(2);
contactsMap.put(contact.id, contact);

View File

@ -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) {

View File

@ -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();

View File

@ -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);
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(FileLoadProgressChanged, arg1, 1.0f);
}
});
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(FileDidLoaded, 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() {
img.callAndClear(operation.image);
if (operation.image != null && memCache.get(arg2) == null) {
memCache.put(arg2, operation.image);
}
NotificationCenter.getInstance().postNotificationName(FileDidLoaded, arg3);
}
});
}
@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;

View File

@ -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)) {

View File

@ -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")) {

View File

@ -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,23 +861,27 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
fileBuffer.rewind();
if (android.os.Build.VERSION.SDK_INT >= 16) {
AutomaticGainControl agc = null;
try {
if (AutomaticGainControl.isAvailable()) {
agc = AutomaticGainControl.create(audioRecorder.getAudioSessionId());
agc.setEnabled(true);
audioGainObj = agc;
}
} catch (Exception e) {
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 (agc != null) {
agc.release();
agc = null;
if (AutomaticGainControl.isAvailable()) {
agc = AutomaticGainControl.create(audioRecorder.getAudioSessionId());
agc.setEnabled(true);
audioGainObj = agc;
}
} catch (Exception e2) {
FileLog.e("tmessages", e2);
} catch (Exception e) {
try {
if (agc != null) {
agc.release();
agc = null;
}
} catch (Exception e2) {
FileLog.e("tmessages", e2);
}
FileLog.e("tmessages", e);
}
FileLog.e("tmessages", 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;
}
}
}

View File

@ -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;
reqSend.media.thumb = new byte[0];
reqSend.media.thumb_h = 0;
reqSend.media.thumb_w = 0;
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;
}
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;
}
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,14 +2080,13 @@ 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;
}
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) {
@ -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);
}
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,12 +2436,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter
FileLoader.getInstance().uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} else if (message.type == 2) {
String location = message.documentLocation.path;
putToDelayedMessages(location, message);
if (message.sendRequest != null) {
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 {
FileLoader.getInstance().uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
String location = message.documentLocation.path;
putToDelayedMessages(location, message);
if (message.sendRequest != null) {
FileLoader.getInstance().uploadFile(location, null, null);
} else {
FileLoader.getInstance().uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
}
} else if (message.type == 3) {
String location = message.audioLocation.path;
@ -2545,8 +2558,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter
performSendMessageRequest(message.sendRequest, message.obj);
}
} else if (message.type == 2) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
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();

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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 = {

View File

@ -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();

View File

@ -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) {

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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,14 +114,69 @@ 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) {
avatarImage = new ImageReceiver();
avatarImage.parentView = new WeakReference<View>(this);
}
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() {
@ -111,10 +185,18 @@ public class ChatBaseCell extends BaseCell {
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,10 +288,14 @@ public class ChatBaseCell extends BaseCell {
}
}
if (currentMessageObject.messageOwner.out) {
currentTimePaint = timePaintOut;
if (!media) {
if (currentMessageObject.messageOwner.out) {
currentTimePaint = timePaintOut;
} else {
currentTimePaint = timePaintIn;
}
} else {
currentTimePaint = timePaintIn;
currentTimePaint = timeMediaPaint;
}
currentTimeString = LocaleController.formatterDay.format((long) (currentMessageObject.messageOwner.date) * 1000);
@ -211,7 +303,7 @@ public class ChatBaseCell extends BaseCell {
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,47 +361,82 @@ 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) {
avatarPressed = true;
result = true;
} else if (drawForwardedName && forwardedNameLayout != null) {
if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32)) {
forwardNamePressed = true;
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) {
if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32)) {
forwardNamePressed = true;
result = true;
}
}
if (result) {
startCheckLongPress();
}
}
} else if (avatarPressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
avatarPressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentUser);
}
} 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)) {
} else {
if (event.getAction() != MotionEvent.ACTION_MOVE) {
cancelCheckLongPress();
}
if (avatarPressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
avatarPressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentUser);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
avatarPressed = false;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (isAvatarVisible && !(x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH)) {
avatarPressed = false;
}
}
}
} else if (forwardNamePressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
forwardNamePressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentForwardUser);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
forwardNamePressed = false;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32))) {
} else if (forwardNamePressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
forwardNamePressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentForwardUser);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
forwardNamePressed = false;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32))) {
forwardNamePressed = false;
}
}
}
}
@ -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 (!currentMessageObject.messageOwner.out) {
timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (chat ? Utilities.dp(52) : 0);
if (!media) {
if (!currentMessageObject.messageOwner.out) {
timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (isChat ? Utilities.dp(52) : 0);
} else {
timeX = layoutWidth - timeWidth - Utilities.dpf(38.5f);
}
} else {
timeX = layoutWidth - timeWidth - Utilities.dpf(38.5f);
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) {
currentBackgroundDrawable = backgroundDrawableOutSelected;
if (!media) {
currentBackgroundDrawable = backgroundDrawableOutSelected;
} else {
currentBackgroundDrawable = backgroundMediaDrawableOutSelected;
}
} else {
currentBackgroundDrawable = backgroundDrawableOut;
if (!media) {
currentBackgroundDrawable = backgroundDrawableOut;
} else {
currentBackgroundDrawable = backgroundMediaDrawableOut;
}
}
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : Utilities.dp(9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
} else {
if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) {
currentBackgroundDrawable = backgroundDrawableInSelected;
if (!media) {
currentBackgroundDrawable = backgroundDrawableInSelected;
} else {
currentBackgroundDrawable = backgroundMediaDrawableInSelected;
}
} else {
currentBackgroundDrawable = backgroundDrawableIn;
if (!media) {
currentBackgroundDrawable = backgroundDrawableIn;
} else {
currentBackgroundDrawable = backgroundMediaDrawableIn;
}
}
if (chat) {
setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
if (isChat) {
setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52 + (!media ? 0 : 9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
} else {
setDrawableBounds(currentBackgroundDrawable, 0, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
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();
}
canvas.save();
canvas.translate(timeX, layoutHeight - Utilities.dpf(6.5f) - timeLayout.getHeight());
timeLayout.draw(canvas);
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) {
setDrawableBounds(clockDrawable, layoutWidth - Utilities.dpf(18.5f) - clockDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - clockDrawable.getIntrinsicHeight());
clockDrawable.draw(canvas);
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 (drawCheck1) {
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(22.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
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 {
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(18.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
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);
}
checkDrawable.draw(canvas);
}
if (drawCheck1) {
setDrawableBounds(halfCheckDrawable, layoutWidth - Utilities.dp(18) - halfCheckDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - halfCheckDrawable.getIntrinsicHeight());
halfCheckDrawable.draw(canvas);
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) {
setDrawableBounds(errorDrawable, layoutWidth - Utilities.dp(18) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(6.5f) - errorDrawable.getIntrinsicHeight());
errorDrawable.draw(canvas);
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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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));

View File

@ -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

View File

@ -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,16 +484,21 @@ 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() {
@Override
public void onClick(View view) {
openAddMenu();
}
});
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 {

View File

@ -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) {

View File

@ -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) {

View File

@ -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();

View File

@ -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 {

View File

@ -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);
}
});
}

View File

@ -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() {

View File

@ -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,10 +238,8 @@ public class LanguageSelectActivity extends BaseFragment {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
if (searchItem != null) {
if (searchItem.isActionViewExpanded()) {
searchItem.collapseActionView();
}
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) {

View File

@ -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);
}
} else {
if (imagesPathArray == null) {
imagesPathArray = new ArrayList<Uri>();
}
imagesPathArray.add((Uri) parcelable);
}
}
imagesPathArray = uris2;
} else {
String[] uris2 = new String[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());
}
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);
}

View File

@ -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) {

View File

@ -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() {

View File

@ -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;
}

View File

@ -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,91 +245,25 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
} else if (i == backgroundRow) {
((LaunchActivity)parentActivity).presentFragment(new SettingsWallpapersActivity(), "settings_wallpapers", false);
} else if (i == askQuestionRow) {
final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
int uid = preferences.getInt("support_id", 0);
TLRPC.User supportUser = null;
if (uid != 0) {
supportUser = MessagesController.getInstance().users.get(uid);
if (supportUser == null) {
String userString = preferences.getString("support_user", null);
if (userString != null) {
try {
byte[] datacentersBytes = Base64.decode(userString, Base64.DEFAULT);
if (datacentersBytes != null) {
SerializedData data = new SerializedData(datacentersBytes);
supportUser = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
}
} catch (Exception e) {
FileLog.e("tmessages", e);
supportUser = null;
}
}
}
if (parentActivity == null) {
return;
}
if (supportUser == null) {
if (parentActivity == null) {
return;
}
final ProgressDialog progressDialog = new ProgressDialog(parentActivity);
progressDialog.setMessage(parentActivity.getString(R.string.Loading));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
progressDialog.show();
TLRPC.TL_help_getSupport req = new TLRPC.TL_help_getSupport();
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
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());
final TLRPC.TL_help_support res = (TLRPC.TL_help_support)response;
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (parentActivity == null) {
return;
}
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("support_id", res.user.id);
SerializedData data = new SerializedData();
res.user.serializeToStream(data);
editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT));
editor.commit();
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
MessagesController.getInstance().users.put(res.user.id, res.user);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", res.user.id);
fragment.setArguments(bundle);
((LaunchActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
});
} else {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
} else {
MessagesController.getInstance().users.putIfAbsent(supportUser.id, supportUser);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", supportUser.id);
fragment.setArguments(bundle);
((LaunchActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
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) {
@ -409,7 +347,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
listView.invalidateViews();
}
} else if (i == languageRow) {
((LaunchActivity)parentActivity).presentFragment(new LanguageSelectActivity(), "settings_wallpapers", false);
((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));
@ -422,11 +360,14 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
});
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);
}
}
// else if (i == 6) {
// UserConfig.saveIncomingPhotos = !UserConfig.saveIncomingPhotos;
// listView.invalidateViews();
// }
}
});
@ -444,12 +385,113 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
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;
if (uid != 0) {
supportUser = MessagesController.getInstance().users.get(uid);
if (supportUser == null) {
String userString = preferences.getString("support_user", null);
if (userString != null) {
try {
byte[] datacentersBytes = Base64.decode(userString, Base64.DEFAULT);
if (datacentersBytes != null) {
SerializedData data = new SerializedData(datacentersBytes);
supportUser = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
}
} catch (Exception e) {
FileLog.e("tmessages", e);
supportUser = null;
}
}
}
}
if (supportUser == null) {
if (parentActivity == null) {
return;
}
final ProgressDialog progressDialog = new ProgressDialog(parentActivity);
progressDialog.setMessage(parentActivity.getString(R.string.Loading));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
progressDialog.show();
TLRPC.TL_help_getSupport req = new TLRPC.TL_help_getSupport();
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final TLRPC.TL_help_support res = (TLRPC.TL_help_support)response;
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (parentActivity == null) {
return;
}
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("support_id", res.user.id);
SerializedData data = new SerializedData();
res.user.serializeToStream(data);
editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT));
editor.commit();
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
MessagesController.getInstance().users.put(res.user.id, res.user);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", res.user.id);
fragment.setArguments(bundle);
((LaunchActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
});
} else {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
} else {
MessagesController.getInstance().users.putIfAbsent(supportUser.id, supportUser);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", supportUser.id);
fragment.setArguments(bundle);
((LaunchActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
}
@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;

View File

@ -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();

View File

@ -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;

View File

@ -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);
}
}
});
@ -168,7 +172,13 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
FileLog.e("tmessages", e);
}
} else {
done = true;
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) {
@ -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 {

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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,7 +162,9 @@ public class BaseFragment extends Fragment {
}
public void onAnimationEnd(Animation animation) {
BaseFragment.this.onAnimationEnd();
if (animationInProgress) {
BaseFragment.this.onAnimationEnd();
}
}
});
@ -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) {
}
}

View File

@ -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];
}
}

View File

@ -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();
}
}

View File

@ -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();
innerPaint = new Paint();
outerPaint = new Paint();
}
innerPaint1.setColor(0xffb4e396);
outerPaint1.setColor(0xff6ac453);
innerPaint2.setColor(0xffd9e2eb);
outerPaint2.setColor(0xff86c5f8);
}
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);
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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