mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcb037122d | |||
| 7eab23aa19 | |||
| 4d839e40ca | |||
| 7a06e3ac0c | |||
| 8392c34f65 | |||
| 67b8486b99 | |||
| 308018e6e6 | |||
| 6c625d078f | |||
| a69afe11f4 | |||
| 4ff15e433b | |||
| 6c81d03c50 | |||
| 9f0b322249 | |||
| e8831b0dfc | |||
| d6e9ba2ea9 | |||
| 2c8c5a7558 | |||
| d2e76a5e61 | |||
| 2263c24019 | |||
| 19e414e65c | |||
| f5a52c1aa2 | |||
| 1cf5039c81 | |||
| 90a5e39872 | |||
| 30868b107e | |||
| 546d4a3bda | |||
| 33eaf71e5b | |||
| a61e73b91b | |||
| f03a3a9b50 | |||
| e2225be331 | |||
| f1f23a5099 | |||
| db3bcb017c | |||
| ab0ce1393e | |||
| b941b9e21a | |||
| b838e0d69e | |||
| 8459f5552d |
@@ -1,5 +1,24 @@
|
||||
# Delta Chat Changelog
|
||||
|
||||
## v0.1.29
|
||||
2017-04-19
|
||||
|
||||
* Add Russian translation
|
||||
* For outgoing (group-)messages, only use the names the receivers have set themselves
|
||||
|
||||
## v0.1.28
|
||||
2017-04-14
|
||||
|
||||
* Pimp notifications
|
||||
* Bug fixes
|
||||
|
||||
## v0.1.27
|
||||
2017-04-12
|
||||
|
||||
* Use a permanent foreground service for reliable notifications
|
||||
* Monitor the IMAP-IDLE thread and reconnect if IMAP-IDLE seems to hang
|
||||
* Various battery and background optimizations
|
||||
|
||||
## v0.1.25
|
||||
2017-04-04
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig.versionCode = 24
|
||||
defaultConfig.versionCode = 29
|
||||
|
||||
sourceSets.main {
|
||||
jniLibs.srcDir 'libs'
|
||||
@@ -117,6 +117,6 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14 // 14: Android 4.0 Ice Cream Sandwich 2011 (Telegram default), 21: Android 5.0 Lollipop 2014 (recommended for InstantRun)
|
||||
targetSdkVersion 25 // 25: Nougat. CAVE: Do NOT target "Andoid O" without checking the background tasks carefully, see https://developer.android.com/preview/behavior-changes.html#back-all . As long as we target "Nougat", everything works as expected even for "Andoid O" or later
|
||||
versionName "0.1.25" // do NOT forget to increase defaultConfig.versionCode!
|
||||
versionName "0.1.29" // do NOT forget to increase defaultConfig.versionCode!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1598,9 +1598,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./jni.c \
|
||||
./mrjnimain.c \
|
||||
./audio.c \
|
||||
./utils.c \
|
||||
./image.c \
|
||||
./video.c \
|
||||
./gifvideo.cpp \
|
||||
|
||||
+64
-40
@@ -1,3 +1,26 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include <stdio.h>
|
||||
@@ -6,7 +29,7 @@
|
||||
#include <time.h>
|
||||
#include <opusfile.h>
|
||||
#include <math.h>
|
||||
#include "utils.h"
|
||||
#include "mrjnimain.h"
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
@@ -115,7 +138,7 @@ static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len) {
|
||||
static int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len) {
|
||||
int i;
|
||||
Packet p;
|
||||
unsigned char ch;
|
||||
@@ -219,34 +242,34 @@ static int writeOggPage(ogg_page *page, FILE *os) {
|
||||
return written;
|
||||
}
|
||||
|
||||
const opus_int32 bitrate = 16000;
|
||||
const opus_int32 rate = 16000;
|
||||
const opus_int32 frame_size = 960;
|
||||
const int with_cvbr = 1;
|
||||
const int max_ogg_delay = 0;
|
||||
const int comment_padding = 512;
|
||||
static const opus_int32 bitrate = 16000;
|
||||
static const opus_int32 rate = 16000;
|
||||
static const opus_int32 frame_size = 960;
|
||||
static const int with_cvbr = 1;
|
||||
static const int max_ogg_delay = 0;
|
||||
static const int comment_padding = 512;
|
||||
|
||||
opus_int32 coding_rate = 16000;
|
||||
ogg_int32_t _packetId;
|
||||
OpusEncoder *_encoder = 0;
|
||||
uint8_t *_packet = 0;
|
||||
ogg_stream_state os;
|
||||
FILE *_fileOs = 0;
|
||||
oe_enc_opt inopt;
|
||||
OpusHeader header;
|
||||
opus_int32 min_bytes;
|
||||
int max_frame_bytes;
|
||||
ogg_packet op;
|
||||
ogg_page og;
|
||||
opus_int64 bytes_written;
|
||||
opus_int64 pages_out;
|
||||
opus_int64 total_samples;
|
||||
ogg_int64_t enc_granulepos;
|
||||
ogg_int64_t last_granulepos;
|
||||
int size_segments;
|
||||
int last_segments;
|
||||
static opus_int32 coding_rate = 16000;
|
||||
static ogg_int32_t _packetId;
|
||||
static OpusEncoder *_encoder = 0;
|
||||
static uint8_t *_packet = 0;
|
||||
static ogg_stream_state os;
|
||||
static FILE *_fileOs = 0;
|
||||
static oe_enc_opt inopt;
|
||||
static OpusHeader header;
|
||||
static opus_int32 min_bytes;
|
||||
static int max_frame_bytes;
|
||||
static ogg_packet op;
|
||||
static ogg_page og;
|
||||
static opus_int64 bytes_written;
|
||||
static opus_int64 pages_out;
|
||||
static opus_int64 total_samples;
|
||||
static ogg_int64_t enc_granulepos;
|
||||
static ogg_int64_t last_granulepos;
|
||||
static int size_segments;
|
||||
static int last_segments;
|
||||
|
||||
void cleanupRecorder() {
|
||||
static void cleanupRecorder() {
|
||||
|
||||
ogg_stream_flush(&os, &og);
|
||||
|
||||
@@ -282,7 +305,7 @@ void cleanupRecorder() {
|
||||
memset(&og, 0, sizeof(ogg_page));
|
||||
}
|
||||
|
||||
int initRecorder(const char *path) {
|
||||
static int initRecorder(const char *path) {
|
||||
cleanupRecorder();
|
||||
|
||||
if (!path) {
|
||||
@@ -421,7 +444,7 @@ int initRecorder(const char *path) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) {
|
||||
static int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) {
|
||||
int cur_frame_size = frame_size;
|
||||
_packetId++;
|
||||
|
||||
@@ -527,15 +550,15 @@ JNIEXPORT void Java_com_b44t_messenger_MediaController_stopRecord(JNIEnv *env, j
|
||||
}
|
||||
|
||||
//player
|
||||
OggOpusFile *_opusFile;
|
||||
int _isSeekable = 0;
|
||||
int64_t _totalPcmDuration = 0;
|
||||
int64_t _currentPcmOffset = 0;
|
||||
int _finished = 0;
|
||||
static OggOpusFile *_opusFile;
|
||||
static int _isSeekable = 0;
|
||||
static int64_t _totalPcmDuration = 0;
|
||||
static int64_t _currentPcmOffset = 0;
|
||||
static int _finished = 0;
|
||||
static const int playerBuffersCount = 3;
|
||||
static const int playerSampleRate = 48000;
|
||||
|
||||
void cleanupPlayer() {
|
||||
static void cleanupPlayer() {
|
||||
if (_opusFile) {
|
||||
op_free(_opusFile);
|
||||
_opusFile = 0;
|
||||
@@ -546,7 +569,7 @@ void cleanupPlayer() {
|
||||
_finished = 0;
|
||||
}
|
||||
|
||||
int seekPlayer(float position) {
|
||||
static int seekPlayer(float position) {
|
||||
if (!_opusFile || !_isSeekable || position < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -559,7 +582,7 @@ int seekPlayer(float position) {
|
||||
return result == OPUS_OK;
|
||||
}
|
||||
|
||||
int initPlayer(const char *path) {
|
||||
static int initPlayer(const char *path) {
|
||||
cleanupPlayer();
|
||||
|
||||
int openError = OPUS_OK;
|
||||
@@ -576,7 +599,7 @@ int initPlayer(const char *path) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void fillBuffer(uint8_t *buffer, int capacity, int *args) {
|
||||
static void fillBuffer(uint8_t *buffer, int capacity, int *args) {
|
||||
if (_opusFile) {
|
||||
args[1] = max(0, op_pcm_tell(_opusFile));
|
||||
|
||||
@@ -735,7 +758,7 @@ JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform2(JNIEnv
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t *sampleBuffer = NULL;
|
||||
static int16_t *sampleBuffer = NULL;
|
||||
|
||||
|
||||
JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) {
|
||||
@@ -819,3 +842,4 @@ JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform(JNIEnv
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <utils.h>
|
||||
#include "mrjnimain.h"
|
||||
#include <libyuv.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <cstdint>
|
||||
@@ -53,19 +76,14 @@ typedef struct VideoInfo {
|
||||
AVPacket orig_pkt;
|
||||
};
|
||||
|
||||
jobject makeGlobarRef(JNIEnv *env, jobject object) {
|
||||
if (object) {
|
||||
return env->NewGlobalRef(object);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env) {
|
||||
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env) { /* called from JNI_OnLoad() */
|
||||
av_register_all();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
|
||||
|
||||
static int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
|
||||
int ret;
|
||||
AVStream *st;
|
||||
AVCodecContext *dec_ctx = NULL;
|
||||
@@ -97,7 +115,7 @@ int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaTy
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decode_packet(VideoInfo *info, int *got_frame) {
|
||||
static int decode_packet(VideoInfo *info, int *got_frame) {
|
||||
int ret = 0;
|
||||
int decoded = info->pkt.size;
|
||||
|
||||
@@ -263,4 +281,5 @@ jint Java_com_b44t_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
+8
-6
@@ -21,11 +21,13 @@
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
package com.b44t.messenger;
|
||||
#ifndef __GIFVIDEO_H__
|
||||
#define __GIFVIDEO_H__
|
||||
|
||||
public class UserObject {
|
||||
|
||||
public static String getUserName(TLRPC.User user) {
|
||||
return "ErrName"; // use MrContact.getName() instead
|
||||
}
|
||||
}
|
||||
#include <jni.h>
|
||||
|
||||
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env);
|
||||
|
||||
|
||||
#endif /* __GIFVIDEO_H__ */
|
||||
+52
-15
@@ -1,3 +1,26 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
@@ -5,21 +28,35 @@
|
||||
#include <android/bitmap.h>
|
||||
#include <libwebp/webp/decode.h>
|
||||
#include <libwebp/webp/encode.h>
|
||||
#include "utils.h"
|
||||
#include "mrjnimain.h"
|
||||
#include "image.h"
|
||||
|
||||
jclass jclass_NullPointerException;
|
||||
jclass jclass_RuntimeException;
|
||||
|
||||
jclass jclass_Options;
|
||||
jfieldID jclass_Options_inJustDecodeBounds;
|
||||
jfieldID jclass_Options_outHeight;
|
||||
jfieldID jclass_Options_outWidth;
|
||||
static jclass jclass_NullPointerException;
|
||||
static jclass jclass_RuntimeException;
|
||||
|
||||
const uint32_t PGPhotoEnhanceHistogramBins = 256;
|
||||
const uint32_t PGPhotoEnhanceSegments = 4;
|
||||
static jclass jclass_Options;
|
||||
static jfieldID jclass_Options_inJustDecodeBounds;
|
||||
static jfieldID jclass_Options_outHeight;
|
||||
static jfieldID jclass_Options_outWidth;
|
||||
|
||||
jclass createGlobarRef(JNIEnv *env, jclass class) {
|
||||
static const uint32_t PGPhotoEnhanceHistogramBins = 256;
|
||||
static const uint32_t PGPhotoEnhanceSegments = 4;
|
||||
|
||||
static void throwException(JNIEnv *env, char *format, ...) {
|
||||
jclass exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
|
||||
if (!exClass) {
|
||||
return;
|
||||
}
|
||||
char dest[256];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsprintf(dest, format, argptr);
|
||||
va_end(argptr);
|
||||
(*env)->ThrowNew(env, exClass, dest);
|
||||
}
|
||||
|
||||
static jclass createGlobalRef(JNIEnv *env, jclass class) {
|
||||
if (class) {
|
||||
return (*env)->NewGlobalRef(env, class);
|
||||
}
|
||||
@@ -27,16 +64,16 @@ jclass createGlobarRef(JNIEnv *env, jclass class) {
|
||||
}
|
||||
|
||||
jint imageOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
|
||||
jclass_NullPointerException = createGlobarRef(env, (*env)->FindClass(env, "java/lang/NullPointerException"));
|
||||
jclass_NullPointerException = createGlobalRef(env, (*env)->FindClass(env, "java/lang/NullPointerException"));
|
||||
if (jclass_NullPointerException == 0) {
|
||||
return -1;
|
||||
}
|
||||
jclass_RuntimeException = createGlobarRef(env, (*env)->FindClass(env, "java/lang/RuntimeException"));
|
||||
jclass_RuntimeException = createGlobalRef(env, (*env)->FindClass(env, "java/lang/RuntimeException"));
|
||||
if (jclass_RuntimeException == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass_Options = createGlobarRef(env, (*env)->FindClass(env, "android/graphics/BitmapFactory$Options"));
|
||||
jclass_Options = createGlobalRef(env, (*env)->FindClass(env, "android/graphics/BitmapFactory$Options"));
|
||||
if (jclass_Options == 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -262,7 +299,7 @@ typedef struct my_error_mgr {
|
||||
} *my_error_ptr;
|
||||
|
||||
|
||||
METHODDEF(void) my_error_exit(j_common_ptr cinfo) {
|
||||
METHODDEF(void) my_jpeglib_error_exit(j_common_ptr cinfo) {
|
||||
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
@@ -424,7 +461,7 @@ JNIEXPORT void Java_com_b44t_messenger_Utilities_loadBitmap(JNIEnv *env, jclass
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
jerr.pub.error_exit = my_jpeglib_error_exit;
|
||||
|
||||
if (!setjmp(jerr.setjmp_buffer)) {
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
#ifndef image_h
|
||||
#define image_h
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef __IMAGE_H__
|
||||
#define __IMAGE_H__
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
jint imageOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __IMAGE_H__ */
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <unistd.h>
|
||||
#include "utils.h"
|
||||
#include "image.h"
|
||||
|
||||
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env);
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) { /* this function is called automatically by the JNI when the library gets loaded */
|
||||
JNIEnv *env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (imageOnJNILoad(vm, reserved, env) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gifvideoOnJNILoad(vm, env) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
JNIEXPORT void Java_com_b44t_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, jboolean encrypt, int offset, int length) {
|
||||
jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset;
|
||||
unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL);
|
||||
unsigned char *ivBuff = (unsigned char *)(*env)->GetByteArrayElements(env, iv, NULL);
|
||||
|
||||
AES_KEY akey;
|
||||
if (!encrypt) {
|
||||
AES_set_decrypt_key(keyBuff, 32 * 8, &akey);
|
||||
AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_DECRYPT);
|
||||
} else {
|
||||
AES_set_encrypt_key(keyBuff, 32 * 8, &akey);
|
||||
AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_ENCRYPT);
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0);
|
||||
}
|
||||
*/
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
|
||||
static char buf[1000];
|
||||
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
int result = readlink(fileName, buf, 999);
|
||||
jstring value = 0;
|
||||
if (result != -1) {
|
||||
buf[result] = '\0';
|
||||
value = (*env)->NewStringUTF(env, buf);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, path, fileName);
|
||||
return value;
|
||||
}
|
||||
@@ -122,13 +122,13 @@
|
||||
#define LIBETPAN_REENTRANT 1
|
||||
|
||||
/* Define this to the version of libEtPan */
|
||||
#define LIBETPAN_VERSION "1.2-dev-20141203"
|
||||
//#define LIBETPAN_VERSION "1.2-dev-20141203"
|
||||
|
||||
/* Define this to the major version of libEtPan */
|
||||
#define LIBETPAN_VERSION_MAJOR 1
|
||||
//#define LIBETPAN_VERSION_MAJOR 1
|
||||
|
||||
/* Define this to the minor version of libEtPan */
|
||||
#define LIBETPAN_VERSION_MINOR 2
|
||||
//#define LIBETPAN_VERSION_MINOR 2
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
@@ -144,7 +144,7 @@
|
||||
#define PACKAGE_NAME "libetpan"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libetpan 1.2"
|
||||
//#define PACKAGE_STRING "libetpan 1.2"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libetpan"
|
||||
@@ -153,7 +153,7 @@
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.2"
|
||||
//#define PACKAGE_VERSION "1.2"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
@@ -171,7 +171,7 @@
|
||||
#define USE_SSL 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.2"
|
||||
//#define VERSION "1.2"
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
|
||||
Submodule MessengerProj/jni/messenger-backend updated: f9451e9946...c128f71f9d
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <unistd.h>
|
||||
#include "mrjnimain.h"
|
||||
#include "image.h"
|
||||
#include "gifvideo.h"
|
||||
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) { /* this function is called automatically by the JNI when the library gets loaded */
|
||||
JNIEnv *env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI_OnLoad() ..."); /* please note, that __android_log_print() may not work (eg. on LG X Cam), however, we don't have an option here. */
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (imageOnJNILoad(vm, reserved, env) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gifvideoOnJNILoad(vm, env) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI_OnLoad() succeeded.");
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
|
||||
static char buf[1000];
|
||||
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
int result = readlink(fileName, buf, 999);
|
||||
jstring value = 0;
|
||||
if (result != -1) {
|
||||
buf[result] = '\0';
|
||||
value = (*env)->NewStringUTF(env, buf);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, path, fileName);
|
||||
return value;
|
||||
}
|
||||
|
||||
+31
-4
@@ -1,6 +1,7 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
@@ -20,8 +21,34 @@
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
package com.b44t.messenger;
|
||||
#ifndef __MRJNIMAIN_H__
|
||||
#define __MRJNIMAIN_H__
|
||||
|
||||
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
|
||||
#define LOG_TAG "DeltaChat"
|
||||
#ifndef LOG_DISABLED
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGI(...)
|
||||
#define LOGD(...)
|
||||
#define LOGE(...)
|
||||
#define LOGV(...)
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(x, y) ((x) > (y)) ? (x) : (y)
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __MRJNIMAIN_H__*/
|
||||
|
||||
public class BuildVars {
|
||||
public static boolean DEBUG_VERSION = false;
|
||||
}
|
||||
@@ -23,8 +23,8 @@
|
||||
* Purpose: The C part of the Java<->C Wrapper, see also MrMailbox.java
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include "messenger-backend/src/mrmailbox.h"
|
||||
@@ -81,6 +81,8 @@ static void s_init_globals(JNIEnv *env, jclass MrMailbox_class)
|
||||
s_global_init_done = 1;
|
||||
|
||||
/* prepare calling back a Java function */
|
||||
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI: s_init_globals()..."); /* low-level logging, mrmailbox_log_*() may not be yet available. However, please note that __android_log_print() may not work (eg. on LG X Cam) */
|
||||
|
||||
(*env)->GetJavaVM(env, &s_jvm); /* JNIEnv cannot be shared between threads, so we share the JavaVM object */
|
||||
s_MrMailbox_class = (*env)->NewGlobalRef(env, MrMailbox_class);
|
||||
s_MrCallback_methodID = (*env)->GetStaticMethodID(env, MrMailbox_class, "MrCallback","(IJJ)J" /*signature as "(param)ret" with I=int, J=long*/ );
|
||||
@@ -108,7 +110,7 @@ void mrosnative_unsetup_thread(mrmailbox_t* mailbox)
|
||||
{
|
||||
mrmailbox_log_info(mailbox, 0, "Detaching C-thread from Java VM...");
|
||||
(*s_jvm)->DetachCurrentThread(s_jvm);
|
||||
mrmailbox_log_info(mailbox, 0, "Detaching done.");
|
||||
mrmailbox_log_info(mailbox, 0, "DeltaChat", "Detaching done.");
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +195,7 @@ static uintptr_t s_mailbox_callback_(mrmailbox_t* mailbox, int event, uintptr_t
|
||||
jlong l;
|
||||
JNIEnv* env;
|
||||
|
||||
#if 0 /* -- __android_log_print() does not log eg. on LG X Cam - but Javas Log.i() etc. do. So, we do not optimize these calls and just use the Java logging. */
|
||||
if( event==MR_EVENT_INFO || event==MR_EVENT_WARNING ) {
|
||||
__android_log_print(event==MR_EVENT_INFO? ANDROID_LOG_INFO : ANDROID_LOG_WARN, "DeltaChat", "%s", (char*)data2); /* on problems, add `-llog` to `Android.mk` */
|
||||
return 0; /* speed up things for info/warning */
|
||||
@@ -201,6 +204,7 @@ static uintptr_t s_mailbox_callback_(mrmailbox_t* mailbox, int event, uintptr_t
|
||||
__android_log_print(ANDROID_LOG_ERROR, "DeltaChat", "%s", (char*)data2);
|
||||
/* errors are also forwarded to Java to show them in a bubble or so */
|
||||
}
|
||||
#endif
|
||||
|
||||
if( s_jvm==NULL || s_MrMailbox_class==NULL || s_MrCallback_methodID==NULL ) {
|
||||
return 0; /* may happen on startup */
|
||||
@@ -518,6 +522,12 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_cmdline(JNIEnv *env, jclass
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_heartbeat(JNIEnv *env, jclass cls)
|
||||
{
|
||||
mrmailbox_heartbeat(get_mrmailbox_t(env, cls));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxAddAddressBook(JNIEnv *env, jclass c, jlong hMailbox, jstring adrbook)
|
||||
{
|
||||
CHAR_REF(adrbook);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "utils.h"
|
||||
|
||||
void throwException(JNIEnv *env, char *format, ...) {
|
||||
jclass exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
|
||||
if (!exClass) {
|
||||
return;
|
||||
}
|
||||
char dest[256];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsprintf(dest, format, argptr);
|
||||
va_end(argptr);
|
||||
(*env)->ThrowNew(env, exClass, dest);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef log_h
|
||||
#define log_h
|
||||
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define LOG_TAG "DeltaChat"
|
||||
#ifndef LOG_DISABLED
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGI(...)
|
||||
#define LOGD(...)
|
||||
#define LOGE(...)
|
||||
#define LOGV(...)
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(x, y) ((x) > (y)) ? (x) : (y)
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#endif
|
||||
|
||||
void throwException(JNIEnv *env, char *format, ...);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,30 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <libyuv.h>
|
||||
#include <utils.h>
|
||||
#include "mrjnimain.h"
|
||||
|
||||
|
||||
enum COLOR_FORMATTYPE {
|
||||
COLOR_FormatMonochrome = 1,
|
||||
@@ -52,7 +76,7 @@ enum COLOR_FORMATTYPE {
|
||||
COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00
|
||||
};
|
||||
|
||||
int isSemiPlanarYUV(int colorFormat) {
|
||||
static int isSemiPlanarYUV(int colorFormat) {
|
||||
switch (colorFormat) {
|
||||
case COLOR_FormatYUV420Planar:
|
||||
case COLOR_FormatYUV420PackedPlanar:
|
||||
|
||||
@@ -51,6 +51,7 @@ import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.StateSet;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
@@ -113,7 +114,7 @@ public class AndroidUtilities {
|
||||
final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
|
||||
final Pattern DOMAIN_NAME = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ public class AndroidUtilities {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ public class AndroidUtilities {
|
||||
prevOrientation = -10;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +220,7 @@ public class AndroidUtilities {
|
||||
InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +235,7 @@ public class AndroidUtilities {
|
||||
}
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +245,7 @@ public class AndroidUtilities {
|
||||
try {
|
||||
state = Environment.getExternalStorageState();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (state == null || state.startsWith(Environment.MEDIA_MOUNTED)) {
|
||||
try {
|
||||
@@ -253,7 +254,7 @@ public class AndroidUtilities {
|
||||
return file;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -262,7 +263,7 @@ public class AndroidUtilities {
|
||||
return file;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return new File("");
|
||||
}
|
||||
@@ -301,11 +302,10 @@ public class AndroidUtilities {
|
||||
if (display != null) {
|
||||
display.getMetrics(displayMetrics);
|
||||
display.getSize(displaySize);
|
||||
FileLog.e("messenger", "display size = " + displaySize.x + " " + displaySize.y + " " + displayMetrics.xdpi + "x" + displayMetrics.ydpi);
|
||||
Log.i("DeltaChat", "Display size: " + displaySize.x + " x " + displaySize.y + ", DPI: " + displayMetrics.xdpi + " x " + displayMetrics.ydpi);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ public class AndroidUtilities {
|
||||
mCursorDrawableRes.setAccessible(true);
|
||||
mCursorDrawableRes.setInt(editText, 0);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ public class AndroidUtilities {
|
||||
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
ApplicationLoader.applicationContext.sendBroadcast(addIntent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ public class AndroidUtilities {
|
||||
addIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
|
||||
ApplicationLoader.applicationContext.sendBroadcast(addIntent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -442,7 +442,7 @@ public class AndroidUtilities {
|
||||
return insets.bottom;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -460,11 +460,11 @@ public class AndroidUtilities {
|
||||
size.set((Integer) mGetRawW.invoke(windowManager.getDefaultDisplay()), (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay()));
|
||||
} catch (Exception e) {
|
||||
size.set(windowManager.getDefaultDisplay().getWidth(), windowManager.getDefaultDisplay().getHeight());
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -560,7 +560,7 @@ public class AndroidUtilities {
|
||||
}
|
||||
return spannableStringBuilder;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return new SpannableStringBuilder(str);
|
||||
}
|
||||
@@ -617,7 +617,7 @@ public class AndroidUtilities {
|
||||
android.content.ClipData clip = android.content.ClipData.newPlainText("label", str);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ public class AndroidUtilities {
|
||||
mediaScanIntent.setData(uri);
|
||||
ApplicationLoader.applicationContext.sendBroadcast(mediaScanIntent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,12 +652,12 @@ public class AndroidUtilities {
|
||||
storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Delta Chat");
|
||||
if (!storageDir.mkdirs()) {
|
||||
if (!storageDir.exists()){
|
||||
FileLog.d("messenger", "failed to create directory");
|
||||
Log.w("DeltaChat", "failed to create directory");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FileLog.d("messenger", "External storage is not mounted READ/WRITE.");
|
||||
Log.w("DeltaChat", "External storage is not mounted READ/WRITE.");
|
||||
}
|
||||
|
||||
return storageDir;
|
||||
@@ -710,7 +710,7 @@ public class AndroidUtilities {
|
||||
return uri.getPath();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -734,7 +734,7 @@ public class AndroidUtilities {
|
||||
return value;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -761,7 +761,7 @@ public class AndroidUtilities {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
|
||||
return new File(storageDir, "IMG_" + timeStamp + ".jpg");
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -772,7 +772,7 @@ public class AndroidUtilities {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
|
||||
return new File(storageDir, "VID_" + timeStamp + ".mp4");
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -802,7 +802,7 @@ public class AndroidUtilities {
|
||||
final int l = Character.digit((char) bytes[++i], 16);
|
||||
buffer.write((char) ((u << 4) + l));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
@@ -813,7 +813,7 @@ public class AndroidUtilities {
|
||||
try {
|
||||
buffer.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return array;
|
||||
}
|
||||
@@ -841,7 +841,7 @@ public class AndroidUtilities {
|
||||
destination = new FileOutputStream(destFile);
|
||||
destination.getChannel().transferFrom(source.getChannel(), 0, source.getChannel().size());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
if (source != null) {
|
||||
|
||||
@@ -133,17 +133,17 @@ public class ApplicationLoader extends Application {
|
||||
path.mkdirs();
|
||||
return path;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return new File("/data/data/com.b44t.messenger/files");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Log.i("DeltaChat", "*************** ApplicationLoader.onCreate() ***************");
|
||||
super.onCreate();
|
||||
applicationContext = getApplicationContext(); // should be set very first as it may be needed eg. for logging
|
||||
|
||||
applicationContext = getApplicationContext();
|
||||
MrMailbox.log_i("DeltaChat", "*************** ApplicationLoader.onCreate() ***************");
|
||||
System.loadLibrary("messenger.1");
|
||||
new ForegroundDetector(this);
|
||||
applicationHandler = new Handler(applicationContext.getMainLooper());
|
||||
@@ -195,28 +195,15 @@ public class ApplicationLoader extends Application {
|
||||
try {
|
||||
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
||||
isScreenOn = pm.isScreenOn();
|
||||
FileLog.e("messenger", "screen state = " + isScreenOn);
|
||||
//Log.i("DeltaChat", "screen state = " + isScreenOn);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
UserConfig.loadConfig();
|
||||
|
||||
// create a timer that wakes up the CPU from time to time
|
||||
try
|
||||
{
|
||||
Intent intent = new Intent(applicationContext, TimerReceiver.class);
|
||||
PendingIntent alarmIntent = PendingIntent.getBroadcast(applicationContext, 0, intent, 0);
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager)applicationContext.getSystemService(Activity.ALARM_SERVICE);
|
||||
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime()+60*1000,
|
||||
60*1000,
|
||||
alarmIntent);
|
||||
}
|
||||
catch( Exception e) {
|
||||
Log.e("DeltaChat", "Cannot create alarm.");
|
||||
}
|
||||
TimerReceiver.scheduleNextAlarm();
|
||||
|
||||
// make sure, the notifications for the "deaddrop" dialog are muted by default
|
||||
SharedPreferences notificationPreferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||
@@ -273,6 +260,6 @@ public class ApplicationLoader extends Application {
|
||||
|
||||
public static void stayAwakeForAMoment()
|
||||
{
|
||||
stayAwakeWakeLock.acquire(10*60*1000); // 10 Minutes to wait for "after chat" messages, after that, we sleep most time, see wakeupWakeLock
|
||||
stayAwakeWakeLock.acquire(1*60*1000); // 1 Minute to wait for "after chat" messages, after that, we sleep most time, see wakeupWakeLock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import android.util.Log;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i("DeltaChat", "*** BootCompletedReceiver.onReceive()");
|
||||
MrMailbox.log_i("DeltaChat", "*** BootCompletedReceiver.onReceive()");
|
||||
// there's nothing more to do here as all initialisation stuff is already done in
|
||||
// ApplicationLoader.onCreate() which is called before this broadcast is sended.
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class ContactsController {
|
||||
pCur.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return allContacts;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DispatchQueue extends Thread {
|
||||
handler.sendMessageDelayed(msg, delay);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -58,7 +58,7 @@ public class DispatchQueue extends Thread {
|
||||
syncLatch.await();
|
||||
handler.removeCallbacks(runnable);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class DispatchQueue extends Thread {
|
||||
handler.postDelayed(runnable, delay);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class DispatchQueue extends Thread {
|
||||
syncLatch.await();
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -117,7 +117,7 @@ public class Emoji {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ public class Emoji {
|
||||
}
|
||||
});
|
||||
} catch (Throwable x) {
|
||||
FileLog.e("messenger", "Error loading emoji", x);
|
||||
//Log.i("DeltaChat", "Error loading emoji", x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public class Emoji {
|
||||
public static EmojiDrawable getEmojiDrawable(CharSequence code) {
|
||||
DrawableInfo info = rects.get(code);
|
||||
if (info == null) {
|
||||
FileLog.e("messenger", "No drawable for emoji " + code);
|
||||
//Log.i("DeltaChat", "No drawable for emoji " + code);
|
||||
return null;
|
||||
}
|
||||
EmojiDrawable ed = new EmojiDrawable(info);
|
||||
@@ -434,7 +434,7 @@ public class Emoji {
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// FileLog.e("messenger", e);
|
||||
//
|
||||
// return cs;
|
||||
// }
|
||||
return s;
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
package com.b44t.messenger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.b44t.messenger.time.FastDateFormat;
|
||||
|
||||
import java.io.File;
|
||||
@@ -37,7 +35,6 @@ public class FileLog {
|
||||
private FastDateFormat dateFormat = null;
|
||||
private DispatchQueue logQueue = null;
|
||||
private File currentFile = null;
|
||||
private File networkFile = null;
|
||||
|
||||
private static volatile FileLog Instance = null;
|
||||
public static FileLog getInstance() {
|
||||
@@ -54,10 +51,7 @@ public class FileLog {
|
||||
}
|
||||
|
||||
public FileLog() {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
dateFormat = FastDateFormat.getInstance("dd_MM_yyyy_HH_mm_ss", Locale.US);
|
||||
dateFormat = FastDateFormat.getInstance("yyyyMMdd_HHmmss", Locale.US);
|
||||
try {
|
||||
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
||||
if (sdCard == null) {
|
||||
@@ -81,37 +75,14 @@ public class FileLog {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getNetworkLogPath() {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
||||
if (sdCard == null) {
|
||||
return "";
|
||||
}
|
||||
File dir = new File(sdCard.getAbsolutePath() + "/logs");
|
||||
dir.mkdirs();
|
||||
getInstance().networkFile = new File(dir, getInstance().dateFormat.format(System.currentTimeMillis()) + "_net.txt");
|
||||
return getInstance().networkFile.getAbsolutePath();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void e(final String tag, final String message, final Throwable exception) {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
Log.e(tag, message, exception);
|
||||
private static void log(final String what, final String tag, final String message)
|
||||
{
|
||||
if (getInstance().streamWriter != null) {
|
||||
getInstance().logQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + message + "\n");
|
||||
getInstance().streamWriter.write(exception.toString());
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " " + what + "/" + tag + ": " + message + "\n");
|
||||
getInstance().streamWriter.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -122,109 +93,14 @@ public class FileLog {
|
||||
}
|
||||
|
||||
public static void e(final String tag, final String message) {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
Log.e(tag, message);
|
||||
if (getInstance().streamWriter != null) {
|
||||
getInstance().logQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + message + "\n");
|
||||
getInstance().streamWriter.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(final String tag, final Throwable e) {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
e.printStackTrace();
|
||||
if (getInstance().streamWriter != null) {
|
||||
getInstance().logQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + e + "\n");
|
||||
StackTraceElement[] stack = e.getStackTrace();
|
||||
for (int a = 0; a < stack.length; a++) {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + stack[a] + "\n");
|
||||
}
|
||||
getInstance().streamWriter.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(final String tag, final String message) {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
Log.d(tag, message);
|
||||
if (getInstance().streamWriter != null) {
|
||||
getInstance().logQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " D/" + tag + "﹕ " + message + "\n");
|
||||
getInstance().streamWriter.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
log("E", tag, message);
|
||||
}
|
||||
|
||||
public static void w(final String tag, final String message) {
|
||||
if (!BuildVars.DEBUG_VERSION) {
|
||||
return;
|
||||
}
|
||||
Log.w(tag, message);
|
||||
if (getInstance().streamWriter != null) {
|
||||
getInstance().logQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " W/" + tag + ": " + message + "\n");
|
||||
getInstance().streamWriter.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
log("W", tag, message);
|
||||
}
|
||||
|
||||
public static void cleanupLogs() {
|
||||
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
|
||||
if (sdCard == null) {
|
||||
return;
|
||||
}
|
||||
File dir = new File (sdCard.getAbsolutePath() + "/logs");
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (int a = 0; a < files.length; a++) {
|
||||
File file = files[a];
|
||||
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
|
||||
continue;
|
||||
}
|
||||
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
|
||||
continue;
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
public static void i(final String tag, final String message) {
|
||||
log("I", tag, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
import com.b44t.ui.Components.AnimatedFileDrawable;
|
||||
|
||||
@@ -158,7 +159,7 @@ public class ImageLoader {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
final BitmapDrawable bitmapDrawable = new BitmapDrawable(originalBitmap);
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@@ -175,7 +176,7 @@ public class ImageLoader {
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
removeTask();
|
||||
}
|
||||
}
|
||||
@@ -237,13 +238,13 @@ public class ImageLoader {
|
||||
}
|
||||
randomAccessFile.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (randomAccessFile != null) {
|
||||
try {
|
||||
randomAccessFile.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,7 +329,7 @@ public class ImageLoader {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@@ -577,7 +578,7 @@ public class ImageLoader {
|
||||
trackAllocation = cl.getMethod("trackExternalAllocation", new Class[]{long.class});
|
||||
trackFree = cl.getMethod("trackExternalFree", new Class[]{long.class});
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
runtime = null;
|
||||
trackAllocation = null;
|
||||
trackFree = null;
|
||||
@@ -752,7 +753,6 @@ public class ImageLoader {
|
||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context arg0, Intent intent) {
|
||||
FileLog.e("messenger", "file system changed");
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
checkMediaPaths();
|
||||
@@ -1170,7 +1170,7 @@ public class ImageLoader {
|
||||
try {
|
||||
path = AndroidUtilities.getPath(uri);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1184,7 +1184,7 @@ public class ImageLoader {
|
||||
inputStream.close();
|
||||
inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1225,7 +1225,7 @@ public class ImageLoader {
|
||||
break;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1244,7 +1244,7 @@ public class ImageLoader {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
ImageLoader.getInstance().clearMemory();
|
||||
try {
|
||||
if (b == null) {
|
||||
@@ -1261,7 +1261,6 @@ public class ImageLoader {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
}
|
||||
} else if (uri != null) {
|
||||
@@ -1278,12 +1277,12 @@ public class ImageLoader {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1386,13 +1385,12 @@ public class ImageLoader {
|
||||
try {
|
||||
return scaleAndSaveImageInternal(cacheFile, bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
ImageLoader.getInstance().clearMemory();
|
||||
System.gc();
|
||||
try {
|
||||
return scaleAndSaveImageInternal(cacheFile, bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
||||
} catch (Throwable e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1450,7 +1448,7 @@ public class ImageLoader {
|
||||
writeFile.write(photoSize.bytes);
|
||||
writeFile.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
TLRPC.TL_photoSize newPhotoSize = new TLRPC.TL_photoSize();
|
||||
|
||||
@@ -483,7 +483,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
||||
currentThumbKey = null;
|
||||
}
|
||||
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
canvas.restore();
|
||||
} else {
|
||||
@@ -528,7 +528,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
||||
currentThumbKey = null;
|
||||
}
|
||||
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
||||
currentThumbKey = null;
|
||||
}
|
||||
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
@@ -580,7 +580,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
||||
drawable.setAlpha(alpha);
|
||||
drawable.draw(canvas);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -662,7 +662,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
||||
checkAlphaAnimation(animationNotReady);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,19 +22,30 @@
|
||||
|
||||
package com.b44t.messenger;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class KeepAliveService extends Service {
|
||||
|
||||
static KeepAliveService s_this = null;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Log.i("DeltaChat", "*** KeepAliveService.onCreate()");
|
||||
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onCreate()");
|
||||
// there's nothing more to do here as all initialisation stuff is already done in
|
||||
// ApplicationLoader.onCreate() which is called before this broadcast is sended.
|
||||
s_this = this;
|
||||
setSelfAsForeground();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,7 +53,7 @@ public class KeepAliveService extends Service {
|
||||
// START_STICKY ensured, the service is recreated as soon it is terminted for any reasons.
|
||||
// as ApplicationLoader.onCreate() is called before a service starts, there is no more to do here,
|
||||
// the app is just running fine.
|
||||
Log.i("DeltaChat", "*** KeepAliveService.onStartCommand()");
|
||||
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onStartCommand()");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@@ -52,7 +63,52 @@ public class KeepAliveService extends Service {
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
Log.i("DeltaChat", "*** KeepAliveService.onDestroy()");
|
||||
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onDestroy()");
|
||||
// the service will be restarted due to START_STICKY automatically, there's nothing more to do.
|
||||
}
|
||||
|
||||
private void setSelfAsForeground() {
|
||||
stopForeground(true);
|
||||
startForeground(FG_NOTIFICATION_ID, createNotification()); // TODO: if we target Android O, we should use startServiceInForeground()
|
||||
}
|
||||
|
||||
static public KeepAliveService getInstance()
|
||||
{
|
||||
return s_this; // may be null
|
||||
}
|
||||
|
||||
/* The notification
|
||||
* A notification is required for a foreground service; and without a foreground service,
|
||||
* Delta Chat won't get new messages reliable
|
||||
**********************************************************************************************/
|
||||
|
||||
public static final int FG_NOTIFICATION_ID = 4142;
|
||||
private Notification createNotification()
|
||||
{
|
||||
// a notification _must_ contain a small icon, a title and a text, see https://developer.android.com/guide/topics/ui/notifiers/notifications.html#Required
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
|
||||
|
||||
if( MrMailbox.isConfigured()!=0) {
|
||||
builder.setContentTitle(LocaleController.formatString("", R.string.PermNotificationTitle, MrMailbox.getConfig("addr", "")));
|
||||
builder.setContentText(getString(R.string.PermNotificationText));
|
||||
}
|
||||
else {
|
||||
builder.setContentTitle(getString(R.string.AppName));
|
||||
builder.setContentText(getString(R.string.AccountNotConfigured));
|
||||
}
|
||||
|
||||
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN ) {
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MIN);
|
||||
}
|
||||
builder.setWhen(0);
|
||||
builder.setSmallIcon(R.drawable.notification_permanent);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void updateForegroundNotification()
|
||||
{
|
||||
// update the notification by simply creating a new notification with the same ID, see https://developer.android.com/training/notify-user/managing.html#Updating
|
||||
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(FG_NOTIFICATION_ID, createNotification());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,12 @@ public class LocaleController {
|
||||
localeInfo.shortName = "hu";
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
localeInfo = new LocaleInfo();
|
||||
localeInfo.name = "Русский";
|
||||
localeInfo.nameEnglish = "Russian";
|
||||
localeInfo.shortName = "ru";
|
||||
languagesDict.put(localeInfo.shortName, localeInfo);
|
||||
|
||||
systemDefaultLocale = Locale.getDefault(); // we have to remember this as we may switch back to default later
|
||||
is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext);
|
||||
LocaleInfo currentInfo = null;
|
||||
@@ -182,14 +188,14 @@ public class LocaleController {
|
||||
}
|
||||
applyLanguage(currentInfo, override);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
IntentFilter timezoneFilter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
ApplicationLoader.applicationContext.registerReceiver(new TimeZoneChangedReceiver(), timezoneFilter);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +277,7 @@ public class LocaleController {
|
||||
changingConfiguration = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
changingConfiguration = false;
|
||||
}
|
||||
recreateFormatters();
|
||||
@@ -305,7 +311,7 @@ public class LocaleController {
|
||||
return String.format(value, args);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return "LOC_ERR: " + key;
|
||||
}
|
||||
}
|
||||
@@ -318,7 +324,7 @@ public class LocaleController {
|
||||
return String.format(string, args);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return "LOC_ERR: " + string;
|
||||
}
|
||||
}
|
||||
@@ -359,7 +365,7 @@ public class LocaleController {
|
||||
}
|
||||
return getInstance().chatFullDate.format(date * 1000);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return "LOC_ERR: formatDateChat";
|
||||
}
|
||||
@@ -421,7 +427,7 @@ public class LocaleController {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return "LOC_ERR";
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
samplesCount = newSamplesCount;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
buffer.position(0);
|
||||
final double amplitude = Math.sqrt(sum / len / 2);
|
||||
@@ -497,14 +497,14 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
freePlayerBuffers.add(new AudioBuffer(playerBufferSize));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
sensorManager = (SensorManager) ApplicationLoader.applicationContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
linearSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
||||
gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
|
||||
if (linearSensor == null || gravitySensor == null) {
|
||||
FileLog.e("messenger", "gravity or linear sensor not found");
|
||||
//Log.i("DeltaChat", "gravity or linear sensor not found");
|
||||
accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
linearSensor = null;
|
||||
gravitySensor = null;
|
||||
@@ -513,7 +513,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
PowerManager powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
||||
proximityWakeLock = powerManager.newWakeLock(0x00000020, "proximity");
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
fileBuffer = ByteBuffer.allocateDirect(1920);
|
||||
recordQueue = new DispatchQueue("recordQueue");
|
||||
@@ -562,12 +562,12 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, new GalleryObserverExternal());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, new GalleryObserverInternal());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -593,7 +593,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
audioTrackPlayer.setStereoVolume(volume, volume);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
progressTimer.cancel();
|
||||
progressTimer = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
progressTimer = new Timer();
|
||||
@@ -687,7 +687,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
currentPlayingMessageObject.audioProgressSec = lastProgress / 1000;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, currentPlayingMessageObject.getId(), value);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,7 +705,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
progressTimer.cancel();
|
||||
progressTimer = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -876,7 +876,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
count = audioTrackPlayer.write(buffer.bufferBytes, 0, buffer.size);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
buffersWrited++;
|
||||
|
||||
@@ -931,7 +931,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
return;
|
||||
}
|
||||
if (event.sensor == proximitySensor) {
|
||||
FileLog.e("messenger", "proximity changed to " + event.values[0]);
|
||||
//Log.i("DeltaChat", "proximity changed to " + event.values[0]);
|
||||
if (lastProximityValue == -100) {
|
||||
lastProximityValue = event.values[0];
|
||||
} else if (lastProximityValue != event.values[0]) {
|
||||
@@ -996,7 +996,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
raisedToTop = 0;
|
||||
countLess = 0;
|
||||
timeSinceRaise = System.currentTimeMillis();
|
||||
//FileLog.e("messenger", "motion detected");
|
||||
//Log.i("DeltaChat", "motion detected");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1013,13 +1013,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
previousAccValue = val;
|
||||
accelerometerVertical = gravityFast[1] > 2.5f && Math.abs(gravityFast[2]) < 4.0f && /*Math.abs(gravityFast[0]) < 9.0f &&*/ Math.abs(gravityFast[0]) > 1.5f;
|
||||
//FileLog.e("messenger", accelerometerVertical + " val = " + val + " acc (" + linearAcceleration[0] + ", " + linearAcceleration[1] + ", " + linearAcceleration[2] + ") grav (" + gravityFast[0] + ", " + gravityFast[1] + ", " + gravityFast[2] + ")");
|
||||
//Log.i("DeltaChat", accelerometerVertical + " val = " + val + " acc (" + linearAcceleration[0] + ", " + linearAcceleration[1] + ", " + linearAcceleration[2] + ") grav (" + gravityFast[0] + ", " + gravityFast[1] + ", " + gravityFast[2] + ")");
|
||||
}
|
||||
if (raisedToBack == minCount && accelerometerVertical && proximityTouched && !NotificationsController.getInstance().audioManager.isWiredHeadsetOn()) {
|
||||
FileLog.e("messenger", "sensor values reached");
|
||||
//Log.i("DeltaChat", "sensor values reached");
|
||||
if (playingMessageObject == null && recordStartRunnable == null && recordingAudio == null && !PhotoViewer.getInstance().isVisible() && ApplicationLoader.isScreenOn && !inputFieldHasText && allowStartRecord && raiseChat != null && !callInProgress) {
|
||||
if (!raiseToEarRecord) {
|
||||
FileLog.e("messenger", "start record");
|
||||
//Log.i("DeltaChat", "start record");
|
||||
useFrontSpeaker = true;
|
||||
if (!raiseChat.playFirstUnreadVoiceMessage() /*if there is nothing to play, the function checks for record permission*/ ) {
|
||||
raiseToEarRecord = true;
|
||||
@@ -1033,7 +1033,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
} /*else if (playingMessageObject != null && playingMessageObject.isVoice()) {
|
||||
if (!useFrontSpeaker) {
|
||||
FileLog.e("messenger", "start listen");
|
||||
//Log.i("DeltaChat", "start listen");
|
||||
if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) {
|
||||
proximityWakeLock.acquire();
|
||||
}
|
||||
@@ -1048,7 +1048,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
} else if (proximityTouched) {
|
||||
/*if (playingMessageObject != null && playingMessageObject.isVoice()) {
|
||||
if (!useFrontSpeaker) {
|
||||
FileLog.e("messenger", "start listen by proximity only");
|
||||
//Log.i("DeltaChat", "start listen by proximity only");
|
||||
if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) {
|
||||
proximityWakeLock.acquire();
|
||||
}
|
||||
@@ -1059,7 +1059,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}*/
|
||||
} else if (!proximityTouched) {
|
||||
if (raiseToEarRecord) {
|
||||
FileLog.e("messenger", "stop record");
|
||||
//Log.i("DeltaChat", "stop record");
|
||||
stopRecording(2);
|
||||
raiseToEarRecord = false;
|
||||
ignoreOnPause = false;
|
||||
@@ -1067,7 +1067,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
proximityWakeLock.release();
|
||||
}
|
||||
} else if (useFrontSpeaker) {
|
||||
FileLog.e("messenger", "stop listen");
|
||||
//Log.i("DeltaChat", "stop listen");
|
||||
useFrontSpeaker = false;
|
||||
startAudioAgain(true);
|
||||
ignoreOnPause = false;
|
||||
@@ -1211,18 +1211,18 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
audioPlayer.reset();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
audioPlayer.stop();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
audioPlayer.release();
|
||||
audioPlayer = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else if (audioTrackPlayer != null) {
|
||||
synchronized (playerObjectSync) {
|
||||
@@ -1230,13 +1230,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
audioTrackPlayer.pause();
|
||||
audioTrackPlayer.flush();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
audioTrackPlayer.release();
|
||||
audioTrackPlayer = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1323,7 +1323,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
seekOpusPlayer(progress);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1457,7 +1457,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
});
|
||||
audioTrackPlayer.play();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
if (audioTrackPlayer != null) {
|
||||
audioTrackPlayer.release();
|
||||
audioTrackPlayer = null;
|
||||
@@ -1488,11 +1488,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
audioInfo = AudioInfo.getAudioInfo(cacheFile);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject != null ? playingMessageObject.getId() : 0);
|
||||
if (audioPlayer != null) {
|
||||
audioPlayer.release();
|
||||
@@ -1526,7 +1526,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
playingMessageObject.audioProgress = 0;
|
||||
playingMessageObject.audioProgressSec = 0;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0);
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
} else if (audioTrackPlayer != null) {
|
||||
if (playingMessageObject.audioProgress == 1) {
|
||||
@@ -1541,7 +1540,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
seekOpusFile(playingMessageObject.audioProgress);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
synchronized (playerSync) {
|
||||
freePlayerBuffers.addAll(usedPlayerBuffers);
|
||||
@@ -1569,7 +1568,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
audioPlayer.reset();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
audioPlayer.stop();
|
||||
} else if (audioTrackPlayer != null) {
|
||||
@@ -1577,7 +1576,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
audioTrackPlayer.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
if (audioPlayer != null) {
|
||||
@@ -1590,7 +1589,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
stopProgressTimer();
|
||||
playingMessageObject = null;
|
||||
@@ -1618,7 +1617,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
isPaused = true;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
isPaused = false;
|
||||
return false;
|
||||
}
|
||||
@@ -1642,7 +1641,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
isPaused = false;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1671,7 +1670,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
v.vibrate(50);
|
||||
//NotificationsController.getInstance().playRecordSound(); -- was also disabled in Telegram; playing a sound while recording may result in a feedback
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
recordQueue.postRunnable(recordStartRunnable = new Runnable() {
|
||||
@@ -1721,7 +1720,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
|
||||
audioRecorder.startRecording();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
recordingAudio = null;
|
||||
stopRecord();
|
||||
recordingAudioFile.delete();
|
||||
@@ -1730,7 +1729,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
audioRecorder.release();
|
||||
audioRecorder = null;
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@@ -1853,7 +1851,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
audioRecorder = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
recordingAudio = null;
|
||||
recordingAudioFile = null;
|
||||
@@ -1874,7 +1872,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
sendAfterDone = send;
|
||||
audioRecorder.stop();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
if (recordingAudioFile != null) {
|
||||
recordingAudioFile.delete();
|
||||
}
|
||||
@@ -1886,7 +1884,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
v.vibrate(50);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||
@Override
|
||||
@@ -1914,14 +1912,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1939,14 +1936,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1962,7 +1958,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -2000,21 +1996,19 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
return f.getAbsolutePath();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
try {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
FileLog.e("messenger", e2);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -2121,13 +2115,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
try {
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2182,13 +2176,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
try {
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2435,7 +2429,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
th.start();
|
||||
th.join();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
@@ -2569,11 +2563,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
} else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
|
||||
processorType = PROCESSOR_TYPE_TI;
|
||||
}
|
||||
FileLog.e("messenger", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
|
||||
//Log.i("DeltaChat", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
|
||||
} else {
|
||||
colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
|
||||
}
|
||||
FileLog.e("messenger", "colorFormat = " + colorFormat);
|
||||
//Log.i("DeltaChat", "colorFormat = " + colorFormat);
|
||||
|
||||
int resultHeightAligned = resultHeight;
|
||||
int padding = 0;
|
||||
@@ -2765,7 +2759,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
|
||||
} else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
MediaFormat newFormat = decoder.getOutputFormat();
|
||||
FileLog.e("messenger", "newFormat = " + newFormat);
|
||||
//Log.i("DeltaChat", "newFormat = " + newFormat);
|
||||
} else if (decoderStatus < 0) {
|
||||
throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
|
||||
} else {
|
||||
@@ -2784,7 +2778,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
if (startTime > 0 && videoTime == -1) {
|
||||
if (info.presentationTimeUs < startTime) {
|
||||
doRender = false;
|
||||
FileLog.e("messenger", "drop frame startTime = " + startTime + " present time = " + info.presentationTimeUs);
|
||||
//Log.i("DeltaChat", "drop frame startTime = " + startTime + " present time = " + info.presentationTimeUs);
|
||||
} else {
|
||||
videoTime = info.presentationTimeUs;
|
||||
}
|
||||
@@ -2796,7 +2790,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
outputSurface.awaitNewImage();
|
||||
} catch (Exception e) {
|
||||
errorWait = true;
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (!errorWait) {
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
@@ -2813,14 +2807,14 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
Utilities.convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV);
|
||||
encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0);
|
||||
} else {
|
||||
FileLog.e("messenger", "input buffer not available");
|
||||
//Log.i("DeltaChat", "input buffer not available");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
decoderOutputAvailable = false;
|
||||
FileLog.e("messenger", "decoder stream end");
|
||||
//Log.i("DeltaChat", "decoder stream end");
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
encoder.signalEndOfInputStream();
|
||||
} else {
|
||||
@@ -2838,7 +2832,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
videoStartTime = videoTime;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
error = true;
|
||||
}
|
||||
|
||||
@@ -2872,7 +2866,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
}
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (extractor != null) {
|
||||
extractor.release();
|
||||
@@ -2881,10 +2875,10 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
||||
try {
|
||||
mediaMuxer.finishMovie(false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
FileLog.e("messenger", "time = " + (System.currentTimeMillis() - time));
|
||||
//Log.i("DeltaChat", "time = " + (System.currentTimeMillis() - time));
|
||||
}
|
||||
} else {
|
||||
preferences.edit().putBoolean("isPreviousOk", true).apply();
|
||||
|
||||
@@ -309,7 +309,7 @@ public class MessageObject {
|
||||
try {
|
||||
Linkify.addLinks((Spannable) caption, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,7 +320,7 @@ public class MessageObject {
|
||||
try {
|
||||
Linkify.addLinks((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +355,7 @@ public class MessageObject {
|
||||
try {
|
||||
textLayout = new StaticLayout(messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ public class MessageObject {
|
||||
block.height = Math.max(block.height, block.textLayout.getLineBottom(block.textLayout.getLineCount() - 1));
|
||||
prevOffset = block.textYOffset;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (a == blocksCount - 1) {
|
||||
@@ -400,7 +400,7 @@ public class MessageObject {
|
||||
try {
|
||||
textHeight = Math.max(textHeight, (int) (block.textYOffset + block.textLayout.getHeight()));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,14 +411,14 @@ public class MessageObject {
|
||||
try {
|
||||
lastLeft = block.textXOffset = block.textLayout.getLineLeft(currentBlockLinesCount - 1);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
float lastLine = 0;
|
||||
try {
|
||||
lastLine = block.textLayout.getLineWidth(currentBlockLinesCount - 1);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
int linesMaxWidth = (int) Math.ceil(lastLine);
|
||||
@@ -441,7 +441,7 @@ public class MessageObject {
|
||||
try {
|
||||
lineWidth = block.textLayout.getLineWidth(n);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
lineWidth = 0;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ public class MessageObject {
|
||||
try {
|
||||
lineLeft = block.textLayout.getLineLeft(n);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
lineLeft = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ public class MrMailbox {
|
||||
|
||||
public native static String getInfo();
|
||||
public native static String cmdline(String cmd);
|
||||
public native static void heartbeat();
|
||||
|
||||
private static long m_hMailbox = 0; // do not rename this, is used in C-part
|
||||
private native static long MrMailboxNew(); // returns hMailbox which must be unref'd after usage (Names as mrmailbox_new don't work due to the additional underscore)
|
||||
@@ -165,6 +166,8 @@ public class MrMailbox {
|
||||
/* receive events
|
||||
**********************************************************************************************/
|
||||
|
||||
public final static int MR_EVENT_INFO = 100;
|
||||
public final static int MR_EVENT_WARNING = 300;
|
||||
public final static int MR_EVENT_ERROR = 400; // INFO and WARNING are blocked in the mrwrapper.c
|
||||
|
||||
public final static int MR_EVENT_MSGS_CHANGED = 2000;
|
||||
@@ -262,7 +265,25 @@ public class MrMailbox {
|
||||
});
|
||||
return 0;
|
||||
|
||||
case MR_EVENT_INFO:
|
||||
Log.i("DeltaChat", CPtr2String(data2));
|
||||
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
|
||||
FileLog.i("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
|
||||
}
|
||||
break;
|
||||
|
||||
case MR_EVENT_WARNING:
|
||||
Log.w("DeltaChat", CPtr2String(data2));
|
||||
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
|
||||
FileLog.w("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
|
||||
}
|
||||
break;
|
||||
|
||||
case MR_EVENT_ERROR:
|
||||
Log.e("DeltaChat", CPtr2String(data2));
|
||||
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
|
||||
FileLog.e("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
|
||||
}
|
||||
synchronized (m_lastErrorLock) {
|
||||
m_lastErrorCode = (int)data1;
|
||||
m_lastErrorString = CPtr2String(data2);
|
||||
@@ -361,6 +382,14 @@ public class MrMailbox {
|
||||
/* additional functions that are not 1:1 available in the backend
|
||||
**********************************************************************************************/
|
||||
|
||||
public static void log_i(String tag, String msg)
|
||||
{
|
||||
Log.i(tag, msg);
|
||||
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
|
||||
FileLog.i(tag, msg); // TODO: Can be removed as soon as notifications are reliable.
|
||||
}
|
||||
}
|
||||
|
||||
public static MrChatlist m_currChatlist = new MrChatlist(0);
|
||||
public native static int getCurrentTime ();
|
||||
public static void reloadMainChatlist()
|
||||
|
||||
@@ -96,7 +96,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
|
||||
remoteControlClient.setTransportControlFlags(RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE |
|
||||
RemoteControlClient.FLAG_KEY_MEDIA_STOP | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
createNotification(messageObject);
|
||||
@@ -182,7 +182,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
|
||||
try {
|
||||
metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover());
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
metadataEditor.apply();
|
||||
|
||||
@@ -150,17 +150,18 @@ public class NotificationCenter {
|
||||
}
|
||||
|
||||
public void postNotificationNameInternal(int id, boolean allowDuringAnimation, Object... args) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
|
||||
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
|
||||
throw new RuntimeException("postNotificationName allowed only from MAIN thread");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!allowDuringAnimation && animationInProgress) {
|
||||
DelayedPost delayedPost = new DelayedPost(id, args);
|
||||
delayedPosts.add(delayedPost);
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.e("messenger", "delay post notification " + id + " with args count = " + args.length);
|
||||
}
|
||||
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
|
||||
Log.i("DeltaChat", "delay post notification " + id + " with args count = " + args.length);
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
broadcasting++;
|
||||
@@ -197,11 +198,11 @@ public class NotificationCenter {
|
||||
}
|
||||
|
||||
public void addObserver(Object observer, int id) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
|
||||
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
|
||||
throw new RuntimeException("addObserver allowed only from MAIN thread");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if (broadcasting != 0) {
|
||||
ArrayList<Object> arrayList = addAfterBroadcast.get(id);
|
||||
if (arrayList == null) {
|
||||
@@ -222,11 +223,11 @@ public class NotificationCenter {
|
||||
}
|
||||
|
||||
public void removeObserver(Object observer, int id) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
|
||||
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
|
||||
throw new RuntimeException("removeObserver allowed only from MAIN thread");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if (broadcasting != 0) {
|
||||
ArrayList<Object> arrayList = removeAfterBroadcast.get(id);
|
||||
if (arrayList == null) {
|
||||
|
||||
@@ -90,6 +90,8 @@ public class NotificationsController {
|
||||
protected AudioManager audioManager;
|
||||
private AlarmManager alarmManager;
|
||||
|
||||
public static final int DEF_LED_COLOR = 0xffffffff;
|
||||
|
||||
private static volatile NotificationsController Instance = null;
|
||||
public static NotificationsController getInstance() {
|
||||
NotificationsController localInstance = Instance;
|
||||
@@ -113,12 +115,12 @@ public class NotificationsController {
|
||||
try {
|
||||
audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -126,13 +128,13 @@ public class NotificationsController {
|
||||
notificationDelayWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "notificationDelayWakelock" /*any name*/);
|
||||
notificationDelayWakelock.setReferenceCounted(false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
notificationDelayRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileLog.e("messenger", "delay reached");
|
||||
//Log.i("DeltaChat", "delay reached");
|
||||
if (!delayedPushMessages.isEmpty()) {
|
||||
showOrUpdateNotification(true);
|
||||
delayedPushMessages.clear();
|
||||
@@ -142,7 +144,7 @@ public class NotificationsController {
|
||||
notificationDelayWakelock.release();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -170,7 +172,7 @@ public class NotificationsController {
|
||||
notificationDelayWakelock.release();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
setBadge(0);
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
||||
@@ -769,12 +771,12 @@ public class NotificationsController {
|
||||
intent.putExtra("badge_count_class_name", launcherClassName);
|
||||
ApplicationLoader.applicationContext.sendBroadcast(intent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -819,7 +821,7 @@ public class NotificationsController {
|
||||
alarmManager.cancel(pintent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,7 +840,7 @@ public class NotificationsController {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -876,7 +878,7 @@ public class NotificationsController {
|
||||
total_unread_count = 0;
|
||||
setBadge(0);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,7 +891,7 @@ public class NotificationsController {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -925,23 +927,23 @@ public class NotificationsController {
|
||||
soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*private void scheduleNotificationDelay(boolean onlineReason) {
|
||||
try {
|
||||
FileLog.e("messenger", "delay notification start, onlineReason = " + onlineReason);
|
||||
//Log.i("DeltaChat", "delay notification start, onlineReason = " + onlineReason);
|
||||
notificationDelayWakelock.acquire(10000);
|
||||
AndroidUtilities.cancelRunOnUIThread(notificationDelayRunnable);
|
||||
AndroidUtilities.runOnUIThread(notificationDelayRunnable, (onlineReason ? 3 * 1000 : 1000));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
showOrUpdateNotification(notifyCheck);
|
||||
}
|
||||
}*/
|
||||
@@ -992,7 +994,7 @@ public class NotificationsController {
|
||||
boolean notifyDisabled = false;
|
||||
int needVibrate = 0;
|
||||
String choosenSoundPath = null;
|
||||
int ledColor = 0xff00ff00;
|
||||
int ledColor = DEF_LED_COLOR;
|
||||
boolean inAppSounds;
|
||||
boolean inAppVibrate;
|
||||
//boolean inAppPreview = false;
|
||||
@@ -1046,7 +1048,7 @@ public class NotificationsController {
|
||||
}
|
||||
needVibrate = preferences.getInt("vibrate_group", 0);
|
||||
priority = preferences.getInt("priority_group", 1);
|
||||
ledColor = preferences.getInt("GroupLed", 0xff00ff00);
|
||||
ledColor = preferences.getInt("GroupLed", DEF_LED_COLOR);
|
||||
} else {
|
||||
if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) {
|
||||
choosenSoundPath = null;
|
||||
@@ -1055,10 +1057,10 @@ public class NotificationsController {
|
||||
}
|
||||
needVibrate = preferences.getInt("vibrate_messages", 0);
|
||||
priority = preferences.getInt("priority_messages", 1);
|
||||
ledColor = preferences.getInt("MessagesLed", 0xff00ff00);
|
||||
ledColor = preferences.getInt("MessagesLed", DEF_LED_COLOR);
|
||||
}
|
||||
if (preferences.contains("color_" + dialog_id)) {
|
||||
ledColor = preferences.getInt("color_" + dialog_id, 0);
|
||||
ledColor = preferences.getInt("color_" + dialog_id, 0/*0=off*/);
|
||||
}
|
||||
|
||||
if (priorityOverride != 3) {
|
||||
@@ -1088,7 +1090,7 @@ public class NotificationsController {
|
||||
needVibrate = 2;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1272,7 +1274,7 @@ public class NotificationsController {
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1336,7 +1338,7 @@ public class NotificationsController {
|
||||
if (chat != null) {
|
||||
name = chat.title;
|
||||
} else {
|
||||
name = UserObject.getUserName(user);
|
||||
name = "ErrName"; // use MrContact.getName(), if really needed
|
||||
}
|
||||
/*if (chat != null) {
|
||||
if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) {
|
||||
@@ -1471,7 +1473,7 @@ public class NotificationsController {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
notificationsQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
@@ -1500,7 +1502,7 @@ public class NotificationsController {
|
||||
soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,10 +33,10 @@ public class ScreenReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
Log.i("DeltaChat", "*** Screen off");
|
||||
MrMailbox.log_i("DeltaChat", "*** Screen off");
|
||||
ApplicationLoader.isScreenOn = false;
|
||||
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
|
||||
Log.i("DeltaChat", "*** Screen on");
|
||||
MrMailbox.log_i("DeltaChat", "*** Screen on");
|
||||
ApplicationLoader.isScreenOn = true;
|
||||
}
|
||||
//NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenStateChanged);
|
||||
|
||||
@@ -358,7 +358,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||
bitmap.recycle();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
if (document.mime_type.equals("image/webp") && allowSticker) {
|
||||
@@ -370,7 +370,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||
Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true);
|
||||
file.close();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (bmOptions.outWidth != 0 && bmOptions.outHeight != 0 && bmOptions.outWidth <= 800 && bmOptions.outHeight <= 800) {
|
||||
TLRPC.TL_documentAttributeSticker attributeSticker = new TLRPC.TL_documentAttributeSticker();
|
||||
@@ -682,14 +682,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||
}
|
||||
infoObtained = true;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (mediaMetadataRetriever != null) {
|
||||
mediaMetadataRetriever.release();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
if (!infoObtained) {
|
||||
@@ -702,7 +702,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
|
||||
mp.release();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,6 @@ public class TLRPC {
|
||||
|
||||
public static class Chat extends TLObject {
|
||||
public int flags;
|
||||
public boolean creator;
|
||||
public int id;
|
||||
public String title;
|
||||
public final ChatPhoto photo = null;
|
||||
|
||||
@@ -22,18 +22,51 @@
|
||||
|
||||
package com.b44t.messenger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class TimerReceiver extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i("DeltaChat", "*** TimerReceiver.onReceive()");
|
||||
|
||||
// acquire for 5 seconds, this should wake un the threads,
|
||||
// acquire for 3 seconds, this should wake up the threads,
|
||||
// _if_ there is more to do, the backend acquires an additional wakelock using MR_EVENT_WAKE_LOCK
|
||||
ApplicationLoader.wakeupWakeLock.acquire(5*1000);
|
||||
ApplicationLoader.wakeupWakeLock.acquire(3*1000); // do this first!
|
||||
MrMailbox.log_i("DeltaChat", "*** TimerReceiver.onReceive()");
|
||||
|
||||
// we assume, the IMAP thread is alive. I cannot imagine, the thread was killed with the App being running.
|
||||
// (if the whole App was killed, the IMAP thread is already started by MrMailbox.connect() if we're here)
|
||||
// (the thread itself will reconnect to the IMAP server as needed)
|
||||
// however, it seems as if the threads sleep longer than ususal, check this by calling heartbeat() manually
|
||||
MrMailbox.heartbeat();
|
||||
|
||||
// create the next alarm in about a minute
|
||||
scheduleNextAlarm();
|
||||
}
|
||||
|
||||
public static void scheduleNextAlarm()
|
||||
{
|
||||
try {
|
||||
Intent intent = new Intent(ApplicationLoader.applicationContext, TimerReceiver.class);
|
||||
PendingIntent alarmIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, intent, 0);
|
||||
|
||||
long triggerAtMillis = System.currentTimeMillis() + 60 * 1000;
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Activity.ALARM_SERVICE);
|
||||
if( Build.VERSION.SDK_INT >= 23 ) {
|
||||
// a simple AlarmManager.set() is no longer send in the new DOZE mode
|
||||
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, alarmIntent);
|
||||
}
|
||||
else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, alarmIntent);
|
||||
}
|
||||
}
|
||||
catch(Exception e) { Log.e("DeltaChat", "Cannot create alarm.", e); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class UserConfig {
|
||||
|
||||
editor.apply();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class UserConfig {
|
||||
passcodeHash = Utilities.bytesToHex(Utilities.computeSHA256(bytes, 0, bytes.length));
|
||||
saveConfig();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -112,7 +112,7 @@ public class UserConfig {
|
||||
String hash = Utilities.bytesToHex(Utilities.computeSHA256(bytes, 0, bytes.length));
|
||||
return passcodeHash.equals(hash);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -56,7 +56,7 @@ public class Utilities {
|
||||
sUrandomIn.close();
|
||||
random.setSeed(buffer);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,15 +67,8 @@ public class Utilities {
|
||||
public native static void calcCDT(ByteBuffer hsvBuffer, int width, int height, ByteBuffer buffer);
|
||||
public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin);
|
||||
public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
|
||||
//private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length);
|
||||
public native static String readlink(String path);
|
||||
|
||||
/*
|
||||
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
|
||||
aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length);
|
||||
}
|
||||
*/
|
||||
|
||||
public static Integer parseInt(String value) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
@@ -88,7 +81,7 @@ public class Utilities {
|
||||
val = Integer.parseInt(num);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -105,19 +98,11 @@ public class Utilities {
|
||||
val = Long.parseLong(num);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static String parseIntToString(String value) {
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "";
|
||||
@@ -132,138 +117,17 @@ public class Utilities {
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public static byte[] hexToBytes(String hex) {
|
||||
if (hex == null) {
|
||||
return null;
|
||||
}
|
||||
int len = hex.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static boolean isGoodPrime(byte[] prime, int g) {
|
||||
if (!(g >= 2 && g <= 7)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prime.length != 256 || prime[0] >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BigInteger dhBI = new BigInteger(1, prime);
|
||||
|
||||
if (g == 2) { // p mod 8 = 7 for g = 2;
|
||||
BigInteger res = dhBI.mod(BigInteger.valueOf(8));
|
||||
if (res.intValue() != 7) {
|
||||
return false;
|
||||
}
|
||||
} else if (g == 3) { // p mod 3 = 2 for g = 3;
|
||||
BigInteger res = dhBI.mod(BigInteger.valueOf(3));
|
||||
if (res.intValue() != 2) {
|
||||
return false;
|
||||
}
|
||||
} else if (g == 5) { // p mod 5 = 1 or 4 for g = 5;
|
||||
BigInteger res = dhBI.mod(BigInteger.valueOf(5));
|
||||
int val = res.intValue();
|
||||
if (val != 1 && val != 4) {
|
||||
return false;
|
||||
}
|
||||
} else if (g == 6) { // p mod 24 = 19 or 23 for g = 6;
|
||||
BigInteger res = dhBI.mod(BigInteger.valueOf(24));
|
||||
int val = res.intValue();
|
||||
if (val != 19 && val != 23) {
|
||||
return false;
|
||||
}
|
||||
} else if (g == 7) { // p mod 7 = 3, 5 or 6 for g = 7.
|
||||
BigInteger res = dhBI.mod(BigInteger.valueOf(7));
|
||||
int val = res.intValue();
|
||||
if (val != 3 && val != 5 && val != 6) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String hex = bytesToHex(prime);
|
||||
if (hex.equals("C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BigInteger dhBI2 = dhBI.subtract(BigInteger.valueOf(1)).divide(BigInteger.valueOf(2));
|
||||
return !(!dhBI.isProbablePrime(30) || !dhBI2.isProbablePrime(30));
|
||||
}
|
||||
|
||||
public static boolean isGoodGaAndGb(BigInteger g_a, BigInteger p) {
|
||||
return !(g_a.compareTo(BigInteger.valueOf(1)) != 1 || g_a.compareTo(p.subtract(BigInteger.valueOf(1))) != -1);
|
||||
}
|
||||
|
||||
public static boolean arraysEquals(byte[] arr1, int offset1, byte[] arr2, int offset2) {
|
||||
if (arr1 == null || arr2 == null || offset1 < 0 || offset2 < 0 || arr1.length - offset1 != arr2.length - offset2 || arr1.length - offset1 < 0 || arr2.length - offset2 < 0) {
|
||||
return false;
|
||||
}
|
||||
boolean result = true;
|
||||
for (int a = offset1; a < arr1.length; a++) {
|
||||
if (arr1[a + offset1] != arr2[a + offset2]) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] computeSHA1(byte[] convertme, int offset, int len) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
md.update(convertme, offset, len);
|
||||
return md.digest();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
}
|
||||
return new byte[20];
|
||||
}
|
||||
|
||||
public static byte[] computeSHA1(ByteBuffer convertme, int offset, int len) {
|
||||
int oldp = convertme.position();
|
||||
int oldl = convertme.limit();
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
convertme.position(offset);
|
||||
convertme.limit(len);
|
||||
md.update(convertme);
|
||||
return md.digest();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
} finally {
|
||||
convertme.limit(oldl);
|
||||
convertme.position(oldp);
|
||||
}
|
||||
return new byte[20];
|
||||
}
|
||||
|
||||
public static byte[] computeSHA1(ByteBuffer convertme) {
|
||||
return computeSHA1(convertme, 0, convertme.limit());
|
||||
}
|
||||
|
||||
public static byte[] computeSHA1(byte[] convertme) {
|
||||
return computeSHA1(convertme, 0, convertme.length);
|
||||
}
|
||||
|
||||
public static byte[] computeSHA256(byte[] convertme, int offset, int len) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(convertme, offset, len);
|
||||
return md.digest();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long bytesToLong(byte[] bytes) {
|
||||
return ((long) bytes[7] << 56) + (((long) bytes[6] & 0xFF) << 48) + (((long) bytes[5] & 0xFF) << 40) + (((long) bytes[4] & 0xFF) << 32)
|
||||
+ (((long) bytes[3] & 0xFF) << 24) + (((long) bytes[2] & 0xFF) << 16) + (((long) bytes[1] & 0xFF) << 8) + ((long) bytes[0] & 0xFF);
|
||||
}
|
||||
|
||||
public static String MD5(String md5) {
|
||||
if (md5 == null) {
|
||||
return null;
|
||||
@@ -277,7 +141,7 @@ public class Utilities {
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (java.security.NoSuchAlgorithmException e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.ui.LaunchActivity;
|
||||
|
||||
public class Browser {
|
||||
@@ -55,7 +54,7 @@ public class Browser {
|
||||
intent.putExtra(android.provider.Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
||||
context.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
||||
import android.support.v4.widget.EdgeEffectCompat;
|
||||
import android.support.v4.widget.ScrollerCompat;
|
||||
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@@ -2050,7 +2049,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
|
||||
edgeEffect.setColor(glowColor);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Error indicating that there was an authentication failure when performing a Request.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AuthFailureError extends VolleyError {
|
||||
/** An intent that can be used to resolve this exception. (Brings up the password dialog.) */
|
||||
private Intent mResolutionIntent;
|
||||
|
||||
public AuthFailureError() { }
|
||||
|
||||
public AuthFailureError(Intent intent) {
|
||||
mResolutionIntent = intent;
|
||||
}
|
||||
|
||||
public AuthFailureError(NetworkResponse response) {
|
||||
super(response);
|
||||
}
|
||||
|
||||
public AuthFailureError(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AuthFailureError(String message, Exception reason) {
|
||||
super(message, reason);
|
||||
}
|
||||
|
||||
public Intent getResolutionIntent() {
|
||||
return mResolutionIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
if (mResolutionIntent != null) {
|
||||
return "User needs to (re)enter credentials.";
|
||||
}
|
||||
return super.getMessage();
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An interface for a cache keyed by a String with a byte array as data.
|
||||
*/
|
||||
public interface Cache {
|
||||
/**
|
||||
* Retrieves an entry from the cache.
|
||||
* @param key Cache key
|
||||
* @return An {@link Entry} or null in the event of a cache miss
|
||||
*/
|
||||
public Entry get(String key);
|
||||
|
||||
/**
|
||||
* Adds or replaces an entry to the cache.
|
||||
* @param key Cache key
|
||||
* @param entry Data to store and metadata for cache coherency, TTL, etc.
|
||||
*/
|
||||
public void put(String key, Entry entry);
|
||||
|
||||
/**
|
||||
* Performs any potentially long-running actions needed to initialize the cache;
|
||||
* will be called from a worker thread.
|
||||
*/
|
||||
public void initialize();
|
||||
|
||||
/**
|
||||
* Invalidates an entry in the cache.
|
||||
* @param key Cache key
|
||||
* @param fullExpire True to fully expire the entry, false to soft expire
|
||||
*/
|
||||
public void invalidate(String key, boolean fullExpire);
|
||||
|
||||
/**
|
||||
* Removes an entry from the cache.
|
||||
* @param key Cache key
|
||||
*/
|
||||
public void remove(String key);
|
||||
|
||||
/**
|
||||
* Empties the cache.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Data and metadata for an entry returned by the cache.
|
||||
*/
|
||||
public static class Entry {
|
||||
/** The data returned from cache. */
|
||||
public byte[] data;
|
||||
|
||||
/** ETag for cache coherency. */
|
||||
public String etag;
|
||||
|
||||
/** Date of this response as reported by the server. */
|
||||
public long serverDate;
|
||||
|
||||
/** The last modified date for the requested object. */
|
||||
public long lastModified;
|
||||
|
||||
/** TTL for this record. */
|
||||
public long ttl;
|
||||
|
||||
/** Soft TTL for this record. */
|
||||
public long softTtl;
|
||||
|
||||
/** Immutable response headers as received from server; must be non-null. */
|
||||
public Map<String, String> responseHeaders = Collections.emptyMap();
|
||||
|
||||
/** True if the entry is expired. */
|
||||
public boolean isExpired() {
|
||||
return this.ttl < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/** True if a refresh is needed from the original data source. */
|
||||
public boolean refreshNeeded() {
|
||||
return this.softTtl < System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.os.Process;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* Provides a thread for performing cache triage on a queue of requests.
|
||||
*
|
||||
* Requests added to the specified cache queue are resolved from cache.
|
||||
* Any deliverable response is posted back to the caller via a
|
||||
* {@link ResponseDelivery}. Cache misses and responses that require
|
||||
* refresh are enqueued on the specified network queue for processing
|
||||
* by a {@link NetworkDispatcher}.
|
||||
*/
|
||||
public class CacheDispatcher extends Thread {
|
||||
|
||||
private static final boolean DEBUG = VolleyLog.DEBUG;
|
||||
|
||||
/** The queue of requests coming in for triage. */
|
||||
private final BlockingQueue<Request<?>> mCacheQueue;
|
||||
|
||||
/** The queue of requests going out to the network. */
|
||||
private final BlockingQueue<Request<?>> mNetworkQueue;
|
||||
|
||||
/** The cache to read from. */
|
||||
private final Cache mCache;
|
||||
|
||||
/** For posting responses. */
|
||||
private final ResponseDelivery mDelivery;
|
||||
|
||||
/** Used for telling us to die. */
|
||||
private volatile boolean mQuit = false;
|
||||
|
||||
/**
|
||||
* Creates a new cache triage dispatcher thread. You must call {@link #start()}
|
||||
* in order to begin processing.
|
||||
*
|
||||
* @param cacheQueue Queue of incoming requests for triage
|
||||
* @param networkQueue Queue to post requests that require network to
|
||||
* @param cache Cache interface to use for resolution
|
||||
* @param delivery Delivery interface to use for posting responses
|
||||
*/
|
||||
public CacheDispatcher(
|
||||
BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
|
||||
Cache cache, ResponseDelivery delivery) {
|
||||
mCacheQueue = cacheQueue;
|
||||
mNetworkQueue = networkQueue;
|
||||
mCache = cache;
|
||||
mDelivery = delivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces this dispatcher to quit immediately. If any requests are still in
|
||||
* the queue, they are not guaranteed to be processed.
|
||||
*/
|
||||
public void quit() {
|
||||
mQuit = true;
|
||||
interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) VolleyLog.v("start new dispatcher");
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
|
||||
// Make a blocking call to initialize the cache.
|
||||
mCache.initialize();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
// Get a request from the cache triage queue, blocking until
|
||||
// at least one is available.
|
||||
final Request<?> request = mCacheQueue.take();
|
||||
request.addMarker("cache-queue-take");
|
||||
|
||||
// If the request has been canceled, don't bother dispatching it.
|
||||
if (request.isCanceled()) {
|
||||
request.finish("cache-discard-canceled");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attempt to retrieve this item from cache.
|
||||
Cache.Entry entry = mCache.get(request.getCacheKey());
|
||||
if (entry == null) {
|
||||
request.addMarker("cache-miss");
|
||||
// Cache miss; send off to the network dispatcher.
|
||||
mNetworkQueue.put(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it is completely expired, just send it to the network.
|
||||
if (entry.isExpired()) {
|
||||
request.addMarker("cache-hit-expired");
|
||||
request.setCacheEntry(entry);
|
||||
mNetworkQueue.put(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a cache hit; parse its data for delivery back to the request.
|
||||
request.addMarker("cache-hit");
|
||||
Response<?> response = request.parseNetworkResponse(
|
||||
new NetworkResponse(entry.data, entry.responseHeaders));
|
||||
request.addMarker("cache-hit-parsed");
|
||||
|
||||
if (!entry.refreshNeeded()) {
|
||||
// Completely unexpired cache hit. Just deliver the response.
|
||||
mDelivery.postResponse(request, response);
|
||||
} else {
|
||||
// Soft-expired cache hit. We can deliver the cached response,
|
||||
// but we need to also send the request to the network for
|
||||
// refreshing.
|
||||
request.addMarker("cache-hit-refresh-needed");
|
||||
request.setCacheEntry(entry);
|
||||
|
||||
// Mark the response as intermediate.
|
||||
response.intermediate = true;
|
||||
|
||||
// Post the intermediate response back to the user and have
|
||||
// the delivery then forward the request along to the network.
|
||||
mDelivery.postResponse(request, response, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mNetworkQueue.put(request);
|
||||
} catch (InterruptedException e) {
|
||||
// Not much we can do about this.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
// We may have been interrupted because it was time to quit.
|
||||
if (mQuit) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Default retry policy for requests.
|
||||
*/
|
||||
public class DefaultRetryPolicy implements RetryPolicy {
|
||||
/** The current timeout in milliseconds. */
|
||||
private int mCurrentTimeoutMs;
|
||||
|
||||
/** The current retry count. */
|
||||
private int mCurrentRetryCount;
|
||||
|
||||
/** The maximum number of attempts. */
|
||||
private final int mMaxNumRetries;
|
||||
|
||||
/** The backoff multiplier for the policy. */
|
||||
private final float mBackoffMultiplier;
|
||||
|
||||
/** The default socket timeout in milliseconds */
|
||||
public static final int DEFAULT_TIMEOUT_MS = 2500;
|
||||
|
||||
/** The default number of retries */
|
||||
public static final int DEFAULT_MAX_RETRIES = 1;
|
||||
|
||||
/** The default backoff multiplier */
|
||||
public static final float DEFAULT_BACKOFF_MULT = 1f;
|
||||
|
||||
/**
|
||||
* Constructs a new retry policy using the default timeouts.
|
||||
*/
|
||||
public DefaultRetryPolicy() {
|
||||
this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new retry policy.
|
||||
* @param initialTimeoutMs The initial timeout for the policy.
|
||||
* @param maxNumRetries The maximum number of retries.
|
||||
* @param backoffMultiplier Backoff multiplier for the policy.
|
||||
*/
|
||||
public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
|
||||
mCurrentTimeoutMs = initialTimeoutMs;
|
||||
mMaxNumRetries = maxNumRetries;
|
||||
mBackoffMultiplier = backoffMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current timeout.
|
||||
*/
|
||||
@Override
|
||||
public int getCurrentTimeout() {
|
||||
return mCurrentTimeoutMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current retry count.
|
||||
*/
|
||||
@Override
|
||||
public int getCurrentRetryCount() {
|
||||
return mCurrentRetryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backoff multiplier for the policy.
|
||||
*/
|
||||
public float getBackoffMultiplier() {
|
||||
return mBackoffMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares for the next retry by applying a backoff to the timeout.
|
||||
* @param error The error code of the last attempt.
|
||||
*/
|
||||
@Override
|
||||
public void retry(VolleyError error) throws VolleyError {
|
||||
mCurrentRetryCount++;
|
||||
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
|
||||
if (!hasAttemptRemaining()) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this policy has attempts remaining, false otherwise.
|
||||
*/
|
||||
protected boolean hasAttemptRemaining() {
|
||||
return mCurrentRetryCount <= mMaxNumRetries;
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.os.Handler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Delivers responses and errors.
|
||||
*/
|
||||
public class ExecutorDelivery implements ResponseDelivery {
|
||||
/** Used for posting responses, typically to the main thread. */
|
||||
private final Executor mResponsePoster;
|
||||
|
||||
/**
|
||||
* Creates a new response delivery interface.
|
||||
* @param handler {@link Handler} to post responses on
|
||||
*/
|
||||
public ExecutorDelivery(final Handler handler) {
|
||||
// Make an Executor that just wraps the handler.
|
||||
mResponsePoster = new Executor() {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
handler.post(command);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new response delivery interface, mockable version
|
||||
* for testing.
|
||||
* @param executor For running delivery tasks
|
||||
*/
|
||||
public ExecutorDelivery(Executor executor) {
|
||||
mResponsePoster = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postResponse(Request<?> request, Response<?> response) {
|
||||
postResponse(request, response, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
|
||||
request.markDelivered();
|
||||
request.addMarker("post-response");
|
||||
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postError(Request<?> request, VolleyError error) {
|
||||
request.addMarker("post-error");
|
||||
Response<?> response = Response.error(error);
|
||||
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* A Runnable used for delivering network responses to a listener on the
|
||||
* main thread.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private class ResponseDeliveryRunnable implements Runnable {
|
||||
private final Request mRequest;
|
||||
private final Response mResponse;
|
||||
private final Runnable mRunnable;
|
||||
|
||||
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
|
||||
mRequest = request;
|
||||
mResponse = response;
|
||||
mRunnable = runnable;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void run() {
|
||||
// If this request has canceled, finish it and don't deliver.
|
||||
if (mRequest.isCanceled()) {
|
||||
mRequest.finish("canceled-at-delivery");
|
||||
return;
|
||||
}
|
||||
|
||||
// Deliver a normal response or error, depending.
|
||||
if (mResponse.isSuccess()) {
|
||||
mRequest.deliverResponse(mResponse.result);
|
||||
} else {
|
||||
mRequest.deliverError(mResponse.error);
|
||||
}
|
||||
|
||||
// If this is an intermediate response, add a marker, otherwise we're done
|
||||
// and the request can be finished.
|
||||
if (mResponse.intermediate) {
|
||||
mRequest.addMarker("intermediate-response");
|
||||
} else {
|
||||
mRequest.finish("done");
|
||||
}
|
||||
|
||||
// If we have been provided a post-delivery runnable, run it.
|
||||
if (mRunnable != null) {
|
||||
mRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* An interface for performing requests.
|
||||
*/
|
||||
public interface Network {
|
||||
/**
|
||||
* Performs the specified request.
|
||||
* @param request Request to process
|
||||
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
|
||||
* @throws VolleyError on errors
|
||||
*/
|
||||
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.net.TrafficStats;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* Provides a thread for performing network dispatch from a queue of requests.
|
||||
*
|
||||
* Requests added to the specified queue are processed from the network via a
|
||||
* specified {@link Network} interface. Responses are committed to cache, if
|
||||
* eligible, using a specified {@link Cache} interface. Valid responses and
|
||||
* errors are posted back to the caller via a {@link ResponseDelivery}.
|
||||
*/
|
||||
public class NetworkDispatcher extends Thread {
|
||||
/** The queue of requests to service. */
|
||||
private final BlockingQueue<Request<?>> mQueue;
|
||||
/** The network interface for processing requests. */
|
||||
private final Network mNetwork;
|
||||
/** The cache to write to. */
|
||||
private final Cache mCache;
|
||||
/** For posting responses and errors. */
|
||||
private final ResponseDelivery mDelivery;
|
||||
/** Used for telling us to die. */
|
||||
private volatile boolean mQuit = false;
|
||||
|
||||
/**
|
||||
* Creates a new network dispatcher thread. You must call {@link #start()}
|
||||
* in order to begin processing.
|
||||
*
|
||||
* @param queue Queue of incoming requests for triage
|
||||
* @param network Network interface to use for performing requests
|
||||
* @param cache Cache interface to use for writing responses to cache
|
||||
* @param delivery Delivery interface to use for posting responses
|
||||
*/
|
||||
public NetworkDispatcher(BlockingQueue<Request<?>> queue,
|
||||
Network network, Cache cache,
|
||||
ResponseDelivery delivery) {
|
||||
mQueue = queue;
|
||||
mNetwork = network;
|
||||
mCache = cache;
|
||||
mDelivery = delivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces this dispatcher to quit immediately. If any requests are still in
|
||||
* the queue, they are not guaranteed to be processed.
|
||||
*/
|
||||
public void quit() {
|
||||
mQuit = true;
|
||||
interrupt();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
private void addTrafficStatsTag(Request<?> request) {
|
||||
// Tag the request (if API >= 14)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
while (true) {
|
||||
long startTimeMs = SystemClock.elapsedRealtime();
|
||||
Request<?> request;
|
||||
try {
|
||||
// Take a request from the queue.
|
||||
request = mQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
// We may have been interrupted because it was time to quit.
|
||||
if (mQuit) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
request.addMarker("network-queue-take");
|
||||
|
||||
// If the request was cancelled already, do not perform the
|
||||
// network request.
|
||||
if (request.isCanceled()) {
|
||||
request.finish("network-discard-cancelled");
|
||||
continue;
|
||||
}
|
||||
|
||||
addTrafficStatsTag(request);
|
||||
|
||||
// Perform the network request.
|
||||
NetworkResponse networkResponse = mNetwork.performRequest(request);
|
||||
request.addMarker("network-http-complete");
|
||||
|
||||
// If the server returned 304 AND we delivered a response already,
|
||||
// we're done -- don't deliver a second identical response.
|
||||
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
|
||||
request.finish("not-modified");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse the response here on the worker thread.
|
||||
Response<?> response = request.parseNetworkResponse(networkResponse);
|
||||
request.addMarker("network-parse-complete");
|
||||
|
||||
// Write to cache if applicable.
|
||||
// TODO: Only update cache metadata instead of entire record for 304s.
|
||||
if (request.shouldCache() && response.cacheEntry != null) {
|
||||
mCache.put(request.getCacheKey(), response.cacheEntry);
|
||||
request.addMarker("network-cache-written");
|
||||
}
|
||||
|
||||
// Post the response back.
|
||||
request.markDelivered();
|
||||
mDelivery.postResponse(request, response);
|
||||
} catch (VolleyError volleyError) {
|
||||
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
|
||||
parseAndDeliverNetworkError(request, volleyError);
|
||||
} catch (Exception e) {
|
||||
VolleyLog.e(e, "Unhandled exception %s", e.toString());
|
||||
VolleyError volleyError = new VolleyError(e);
|
||||
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
|
||||
mDelivery.postError(request, volleyError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
|
||||
error = request.parseNetworkError(error);
|
||||
mDelivery.postError(request, error);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Indicates that there was a network error when performing a Volley request.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NetworkError extends VolleyError {
|
||||
public NetworkError() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NetworkError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NetworkError(NetworkResponse networkResponse) {
|
||||
super(networkResponse);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Data and headers returned from {@link Network#performRequest(Request)}.
|
||||
*/
|
||||
public class NetworkResponse {
|
||||
/**
|
||||
* Creates a new network response.
|
||||
* @param statusCode the HTTP status code
|
||||
* @param data Response body
|
||||
* @param headers Headers returned with this response, or null for none
|
||||
* @param notModified True if the server returned a 304 and the data was already in cache
|
||||
* @param networkTimeMs Round-trip network time to receive network response
|
||||
*/
|
||||
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
|
||||
boolean notModified, long networkTimeMs) {
|
||||
this.statusCode = statusCode;
|
||||
this.data = data;
|
||||
this.headers = headers;
|
||||
this.notModified = notModified;
|
||||
this.networkTimeMs = networkTimeMs;
|
||||
}
|
||||
|
||||
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
|
||||
boolean notModified) {
|
||||
this(statusCode, data, headers, notModified, 0);
|
||||
}
|
||||
|
||||
public NetworkResponse(byte[] data) {
|
||||
this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);
|
||||
}
|
||||
|
||||
public NetworkResponse(byte[] data, Map<String, String> headers) {
|
||||
this(HttpStatus.SC_OK, data, headers, false, 0);
|
||||
}
|
||||
|
||||
/** The HTTP status code. */
|
||||
public final int statusCode;
|
||||
|
||||
/** Raw data from this response. */
|
||||
public final byte[] data;
|
||||
|
||||
/** Response headers. */
|
||||
public final Map<String, String> headers;
|
||||
|
||||
/** True if the server returned a 304 (Not Modified). */
|
||||
public final boolean notModified;
|
||||
|
||||
/** Network roundtrip time in milliseconds. */
|
||||
public final long networkTimeMs;
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Error indicating that no connection could be established when performing a Volley request.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NoConnectionError extends NetworkError {
|
||||
public NoConnectionError() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NoConnectionError(Throwable reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Indicates that the server's response could not be parsed.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ParseError extends VolleyError {
|
||||
public ParseError() { }
|
||||
|
||||
public ParseError(NetworkResponse networkResponse) {
|
||||
super(networkResponse);
|
||||
}
|
||||
|
||||
public ParseError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -1,589 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.net.TrafficStats;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.b44t.messenger.volley.VolleyLog.MarkerLog;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for all network requests.
|
||||
*
|
||||
* @param <T> The type of parsed response this request expects.
|
||||
*/
|
||||
public abstract class Request<T> implements Comparable<Request<T>> {
|
||||
|
||||
/**
|
||||
* Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}.
|
||||
*/
|
||||
private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
|
||||
|
||||
/**
|
||||
* Supported request methods.
|
||||
*/
|
||||
public interface Method {
|
||||
int DEPRECATED_GET_OR_POST = -1;
|
||||
int GET = 0;
|
||||
int POST = 1;
|
||||
int PUT = 2;
|
||||
int DELETE = 3;
|
||||
int HEAD = 4;
|
||||
int OPTIONS = 5;
|
||||
int TRACE = 6;
|
||||
int PATCH = 7;
|
||||
}
|
||||
|
||||
/** An event log tracing the lifetime of this request; for debugging. */
|
||||
private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;
|
||||
|
||||
/**
|
||||
* Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,
|
||||
* TRACE, and PATCH.
|
||||
*/
|
||||
private final int mMethod;
|
||||
|
||||
/** URL of this request. */
|
||||
private final String mUrl;
|
||||
|
||||
/** Default tag for {@link TrafficStats}. */
|
||||
private final int mDefaultTrafficStatsTag;
|
||||
|
||||
/** Listener interface for errors. */
|
||||
private final Response.ErrorListener mErrorListener;
|
||||
|
||||
/** Sequence number of this request, used to enforce FIFO ordering. */
|
||||
private Integer mSequence;
|
||||
|
||||
/** The request queue this request is associated with. */
|
||||
private RequestQueue mRequestQueue;
|
||||
|
||||
/** Whether or not responses to this request should be cached. */
|
||||
private boolean mShouldCache = true;
|
||||
|
||||
/** Whether or not this request has been canceled. */
|
||||
private boolean mCanceled = false;
|
||||
|
||||
/** Whether or not a response has been delivered for this request yet. */
|
||||
private boolean mResponseDelivered = false;
|
||||
|
||||
/** The retry policy for this request. */
|
||||
private RetryPolicy mRetryPolicy;
|
||||
|
||||
/**
|
||||
* When a request can be retrieved from cache but must be refreshed from
|
||||
* the network, the cache entry will be stored here so that in the event of
|
||||
* a "Not Modified" response, we can be sure it hasn't been evicted from cache.
|
||||
*/
|
||||
private Cache.Entry mCacheEntry = null;
|
||||
|
||||
/** An opaque token tagging this request; used for bulk cancellation. */
|
||||
private Object mTag;
|
||||
|
||||
/**
|
||||
* Creates a new request with the given URL and error listener. Note that
|
||||
* the normal response listener is not provided here as delivery of responses
|
||||
* is provided by subclasses, who have a better idea of how to deliver an
|
||||
* already-parsed response.
|
||||
*
|
||||
* @deprecated Use {@link #Request(int, String, com.android.volley.Response.ErrorListener)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public Request(String url, Response.ErrorListener listener) {
|
||||
this(Method.DEPRECATED_GET_OR_POST, url, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new request with the given method (one of the values from {@link Method}),
|
||||
* URL, and error listener. Note that the normal response listener is not provided here as
|
||||
* delivery of responses is provided by subclasses, who have a better idea of how to deliver
|
||||
* an already-parsed response.
|
||||
*/
|
||||
public Request(int method, String url, Response.ErrorListener listener) {
|
||||
mMethod = method;
|
||||
mUrl = url;
|
||||
mErrorListener = listener;
|
||||
setRetryPolicy(new DefaultRetryPolicy());
|
||||
|
||||
mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method for this request. Can be one of the values in {@link Method}.
|
||||
*/
|
||||
public int getMethod() {
|
||||
return mMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a tag on this request. Can be used to cancel all requests with this
|
||||
* tag by {@link RequestQueue#cancelAll(Object)}.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public Request<?> setTag(Object tag) {
|
||||
mTag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this request's tag.
|
||||
* @see Request#setTag(Object)
|
||||
*/
|
||||
public Object getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return this request's {@link com.android.volley.Response.ErrorListener}.
|
||||
*/
|
||||
public Response.ErrorListener getErrorListener() {
|
||||
return mErrorListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)}
|
||||
*/
|
||||
public int getTrafficStatsTag() {
|
||||
return mDefaultTrafficStatsTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The hashcode of the URL's host component, or 0 if there is none.
|
||||
*/
|
||||
private static int findDefaultTrafficStatsTag(String url) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
Uri uri = Uri.parse(url);
|
||||
if (uri != null) {
|
||||
String host = uri.getHost();
|
||||
if (host != null) {
|
||||
return host.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the retry policy for this request.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
|
||||
mRetryPolicy = retryPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event to this request's event log; for debugging.
|
||||
*/
|
||||
public void addMarker(String tag) {
|
||||
if (MarkerLog.ENABLED) {
|
||||
mEventLog.add(tag, Thread.currentThread().getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the request queue that this request has finished (successfully or with error).
|
||||
*
|
||||
* <p>Also dumps all events from this request's event log; for debugging.</p>
|
||||
*/
|
||||
void finish(final String tag) {
|
||||
if (mRequestQueue != null) {
|
||||
mRequestQueue.finish(this);
|
||||
}
|
||||
if (MarkerLog.ENABLED) {
|
||||
final long threadId = Thread.currentThread().getId();
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
// If we finish marking off of the main thread, we need to
|
||||
// actually do it on the main thread to ensure correct ordering.
|
||||
Handler mainThread = new Handler(Looper.getMainLooper());
|
||||
mainThread.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mEventLog.add(tag, threadId);
|
||||
mEventLog.finish(this.toString());
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
mEventLog.add(tag, threadId);
|
||||
mEventLog.finish(this.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates this request with the given queue. The request queue will be notified when this
|
||||
* request has finished.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public Request<?> setRequestQueue(RequestQueue requestQueue) {
|
||||
mRequestQueue = requestQueue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sequence number of this request. Used by {@link RequestQueue}.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public final Request<?> setSequence(int sequence) {
|
||||
mSequence = sequence;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sequence number of this request.
|
||||
*/
|
||||
public final int getSequence() {
|
||||
if (mSequence == null) {
|
||||
throw new IllegalStateException("getSequence called before setSequence");
|
||||
}
|
||||
return mSequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of this request.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache key for this request. By default, this is the URL.
|
||||
*/
|
||||
public String getCacheKey() {
|
||||
return getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates this request with an entry retrieved for it from cache.
|
||||
* Used for cache coherency support.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public Request<?> setCacheEntry(Cache.Entry entry) {
|
||||
mCacheEntry = entry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the annotated cache entry, or null if there isn't one.
|
||||
*/
|
||||
public Cache.Entry getCacheEntry() {
|
||||
return mCacheEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this request as canceled. No callback will be delivered.
|
||||
*/
|
||||
public void cancel() {
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this request has been canceled.
|
||||
*/
|
||||
public boolean isCanceled() {
|
||||
return mCanceled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of extra HTTP headers to go along with this request. Can
|
||||
* throw {@link AuthFailureError} as authentication may be required to
|
||||
* provide these values.
|
||||
* @throws AuthFailureError In the event of auth failure
|
||||
*/
|
||||
public Map<String, String> getHeaders() throws AuthFailureError {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of POST parameters to be used for this request, or null if
|
||||
* a simple GET should be used. Can throw {@link AuthFailureError} as
|
||||
* authentication may be required to provide these values.
|
||||
*
|
||||
* <p>Note that only one of getPostParams() and getPostBody() can return a non-null
|
||||
* value.</p>
|
||||
* @throws AuthFailureError In the event of auth failure
|
||||
*
|
||||
* @deprecated Use {@link #getParams()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, String> getPostParams() throws AuthFailureError {
|
||||
return getParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which encoding should be used when converting POST parameters returned by
|
||||
* {@link #getPostParams()} into a raw POST body.
|
||||
*
|
||||
* <p>This controls both encodings:
|
||||
* <ol>
|
||||
* <li>The string encoding used when converting parameter names and values into bytes prior
|
||||
* to URL encoding them.</li>
|
||||
* <li>The string encoding used when converting the URL encoded parameters into a raw
|
||||
* byte array.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @deprecated Use {@link #getParamsEncoding()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected String getPostParamsEncoding() {
|
||||
return getParamsEncoding();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getBodyContentType()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getPostBodyContentType() {
|
||||
return getBodyContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw POST body to be sent.
|
||||
*
|
||||
* @throws AuthFailureError In the event of auth failure
|
||||
*
|
||||
* @deprecated Use {@link #getBody()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public byte[] getPostBody() throws AuthFailureError {
|
||||
// Note: For compatibility with legacy clients of volley, this implementation must remain
|
||||
// here instead of simply calling the getBody() function because this function must
|
||||
// call getPostParams() and getPostParamsEncoding() since legacy clients would have
|
||||
// overridden these two member functions for POST requests.
|
||||
Map<String, String> postParams = getPostParams();
|
||||
if (postParams != null && postParams.size() > 0) {
|
||||
return encodeParameters(postParams, getPostParamsEncoding());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of parameters to be used for a POST or PUT request. Can throw
|
||||
* {@link AuthFailureError} as authentication may be required to provide these values.
|
||||
*
|
||||
* <p>Note that you can directly override {@link #getBody()} for custom data.</p>
|
||||
*
|
||||
* @throws AuthFailureError in the event of auth failure
|
||||
*/
|
||||
protected Map<String, String> getParams() throws AuthFailureError {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which encoding should be used when converting POST or PUT parameters returned by
|
||||
* {@link #getParams()} into a raw POST or PUT body.
|
||||
*
|
||||
* <p>This controls both encodings:
|
||||
* <ol>
|
||||
* <li>The string encoding used when converting parameter names and values into bytes prior
|
||||
* to URL encoding them.</li>
|
||||
* <li>The string encoding used when converting the URL encoded parameters into a raw
|
||||
* byte array.</li>
|
||||
* </ol>
|
||||
*/
|
||||
protected String getParamsEncoding() {
|
||||
return DEFAULT_PARAMS_ENCODING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content type of the POST or PUT body.
|
||||
*/
|
||||
public String getBodyContentType() {
|
||||
return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw POST or PUT body to be sent.
|
||||
*
|
||||
* <p>By default, the body consists of the request parameters in
|
||||
* application/x-www-form-urlencoded format. When overriding this method, consider overriding
|
||||
* {@link #getBodyContentType()} as well to match the new body format.
|
||||
*
|
||||
* @throws AuthFailureError in the event of auth failure
|
||||
*/
|
||||
public byte[] getBody() throws AuthFailureError {
|
||||
Map<String, String> params = getParams();
|
||||
if (params != null && params.size() > 0) {
|
||||
return encodeParameters(params, getParamsEncoding());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
|
||||
*/
|
||||
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
|
||||
StringBuilder encodedParams = new StringBuilder();
|
||||
try {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
|
||||
encodedParams.append('=');
|
||||
encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
|
||||
encodedParams.append('&');
|
||||
}
|
||||
return encodedParams.toString().getBytes(paramsEncoding);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not responses to this request should be cached.
|
||||
*
|
||||
* @return This Request object to allow for chaining.
|
||||
*/
|
||||
public final Request<?> setShouldCache(boolean shouldCache) {
|
||||
mShouldCache = shouldCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if responses to this request should be cached.
|
||||
*/
|
||||
public final boolean shouldCache() {
|
||||
return mShouldCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority values. Requests will be processed from higher priorities to
|
||||
* lower priorities, in FIFO order.
|
||||
*/
|
||||
public enum Priority {
|
||||
LOW,
|
||||
NORMAL,
|
||||
HIGH,
|
||||
IMMEDIATE
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default.
|
||||
*/
|
||||
public Priority getPriority() {
|
||||
return Priority.NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the socket timeout in milliseconds per retry attempt. (This value can be changed
|
||||
* per retry attempt if a backoff is specified via backoffTimeout()). If there are no retry
|
||||
* attempts remaining, this will cause delivery of a {@link TimeoutError} error.
|
||||
*/
|
||||
public final int getTimeoutMs() {
|
||||
return mRetryPolicy.getCurrentTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the retry policy that should be used for this request.
|
||||
*/
|
||||
public RetryPolicy getRetryPolicy() {
|
||||
return mRetryPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this request as having a response delivered on it. This can be used
|
||||
* later in the request's lifetime for suppressing identical responses.
|
||||
*/
|
||||
public void markDelivered() {
|
||||
mResponseDelivered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this request has had a response delivered for it.
|
||||
*/
|
||||
public boolean hasHadResponseDelivered() {
|
||||
return mResponseDelivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this to parse the raw network response
|
||||
* and return an appropriate response type. This method will be
|
||||
* called from a worker thread. The response will not be delivered
|
||||
* if you return null.
|
||||
* @param response Response from the network
|
||||
* @return The parsed response, or null in the case of an error
|
||||
*/
|
||||
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to parse 'networkError' and return a more specific error.
|
||||
*
|
||||
* <p>The default implementation just returns the passed 'networkError'.</p>
|
||||
*
|
||||
* @param volleyError the error retrieved from the network
|
||||
* @return an NetworkError augmented with additional information
|
||||
*/
|
||||
protected VolleyError parseNetworkError(VolleyError volleyError) {
|
||||
return volleyError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this to perform delivery of the parsed
|
||||
* response to their listeners. The given response is guaranteed to
|
||||
* be non-null; responses that fail to parse are not delivered.
|
||||
* @param response The parsed response returned by
|
||||
* {@link #parseNetworkResponse(NetworkResponse)}
|
||||
*/
|
||||
abstract protected void deliverResponse(T response);
|
||||
|
||||
/**
|
||||
* Delivers error message to the ErrorListener that the Request was
|
||||
* initialized with.
|
||||
*
|
||||
* @param error Error details
|
||||
*/
|
||||
public void deliverError(VolleyError error) {
|
||||
if (mErrorListener != null) {
|
||||
mErrorListener.onErrorResponse(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Our comparator sorts from high to low priority, and secondarily by
|
||||
* sequence number to provide FIFO ordering.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Request<T> other) {
|
||||
Priority left = this.getPriority();
|
||||
Priority right = other.getPriority();
|
||||
|
||||
// High-priority requests are "lesser" so they are sorted to the front.
|
||||
// Equal priorities are sorted by sequence number to provide FIFO ordering.
|
||||
return left == right ?
|
||||
this.mSequence - other.mSequence :
|
||||
right.ordinal() - left.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String trafficStatsTag = "0x" + Integer.toHexString(getTrafficStatsTag());
|
||||
return (mCanceled ? "[X] " : "[ ] ") + getUrl() + " " + trafficStatsTag + " "
|
||||
+ getPriority() + " " + mSequence;
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* A request dispatch queue with a thread pool of dispatchers.
|
||||
*
|
||||
* Calling {@link #add(Request)} will enqueue the given Request for dispatch,
|
||||
* resolving from either cache or network on a worker thread, and then delivering
|
||||
* a parsed response on the main thread.
|
||||
*/
|
||||
public class RequestQueue {
|
||||
|
||||
/** Callback interface for completed requests. */
|
||||
public static interface RequestFinishedListener<T> {
|
||||
/** Called when a request has finished processing. */
|
||||
public void onRequestFinished(Request<T> request);
|
||||
}
|
||||
|
||||
/** Used for generating monotonically-increasing sequence numbers for requests. */
|
||||
private AtomicInteger mSequenceGenerator = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* Staging area for requests that already have a duplicate request in flight.
|
||||
*
|
||||
* <ul>
|
||||
* <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache
|
||||
* key.</li>
|
||||
* <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request
|
||||
* is <em>not</em> contained in that list. Is null if no requests are staged.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private final Map<String, Queue<Request<?>>> mWaitingRequests =
|
||||
new HashMap<String, Queue<Request<?>>>();
|
||||
|
||||
/**
|
||||
* The set of all requests currently being processed by this RequestQueue. A Request
|
||||
* will be in this set if it is waiting in any queue or currently being processed by
|
||||
* any dispatcher.
|
||||
*/
|
||||
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
|
||||
|
||||
/** The cache triage queue. */
|
||||
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
|
||||
new PriorityBlockingQueue<Request<?>>();
|
||||
|
||||
/** The queue of requests that are actually going out to the network. */
|
||||
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
|
||||
new PriorityBlockingQueue<Request<?>>();
|
||||
|
||||
/** Number of network request dispatcher threads to start. */
|
||||
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
|
||||
|
||||
/** Cache interface for retrieving and storing responses. */
|
||||
private final Cache mCache;
|
||||
|
||||
/** Network interface for performing requests. */
|
||||
private final Network mNetwork;
|
||||
|
||||
/** Response delivery mechanism. */
|
||||
private final ResponseDelivery mDelivery;
|
||||
|
||||
/** The network dispatchers. */
|
||||
private NetworkDispatcher[] mDispatchers;
|
||||
|
||||
/** The cache dispatcher. */
|
||||
private CacheDispatcher mCacheDispatcher;
|
||||
|
||||
private List<RequestFinishedListener> mFinishedListeners =
|
||||
new ArrayList<RequestFinishedListener>();
|
||||
|
||||
/**
|
||||
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
|
||||
*
|
||||
* @param cache A Cache to use for persisting responses to disk
|
||||
* @param network A Network interface for performing HTTP requests
|
||||
* @param threadPoolSize Number of network dispatcher threads to create
|
||||
* @param delivery A ResponseDelivery interface for posting responses and errors
|
||||
*/
|
||||
public RequestQueue(Cache cache, Network network, int threadPoolSize,
|
||||
ResponseDelivery delivery) {
|
||||
mCache = cache;
|
||||
mNetwork = network;
|
||||
mDispatchers = new NetworkDispatcher[threadPoolSize];
|
||||
mDelivery = delivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
|
||||
*
|
||||
* @param cache A Cache to use for persisting responses to disk
|
||||
* @param network A Network interface for performing HTTP requests
|
||||
* @param threadPoolSize Number of network dispatcher threads to create
|
||||
*/
|
||||
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
|
||||
this(cache, network, threadPoolSize,
|
||||
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
|
||||
*
|
||||
* @param cache A Cache to use for persisting responses to disk
|
||||
* @param network A Network interface for performing HTTP requests
|
||||
*/
|
||||
public RequestQueue(Cache cache, Network network) {
|
||||
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the dispatchers in this queue.
|
||||
*/
|
||||
public void start() {
|
||||
stop(); // Make sure any currently running dispatchers are stopped.
|
||||
// Create the cache dispatcher and start it.
|
||||
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
|
||||
mCacheDispatcher.start();
|
||||
|
||||
// Create network dispatchers (and corresponding threads) up to the pool size.
|
||||
for (int i = 0; i < mDispatchers.length; i++) {
|
||||
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
|
||||
mCache, mDelivery);
|
||||
mDispatchers[i] = networkDispatcher;
|
||||
networkDispatcher.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the cache and network dispatchers.
|
||||
*/
|
||||
public void stop() {
|
||||
if (mCacheDispatcher != null) {
|
||||
mCacheDispatcher.quit();
|
||||
}
|
||||
for (int i = 0; i < mDispatchers.length; i++) {
|
||||
if (mDispatchers[i] != null) {
|
||||
mDispatchers[i].quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sequence number.
|
||||
*/
|
||||
public int getSequenceNumber() {
|
||||
return mSequenceGenerator.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Cache} instance being used.
|
||||
*/
|
||||
public Cache getCache() {
|
||||
return mCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple predicate or filter interface for Requests, for use by
|
||||
* {@link RequestQueue#cancelAll(RequestFilter)}.
|
||||
*/
|
||||
public interface RequestFilter {
|
||||
public boolean apply(Request<?> request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all requests in this queue for which the given filter applies.
|
||||
* @param filter The filtering function to use
|
||||
*/
|
||||
public void cancelAll(RequestFilter filter) {
|
||||
synchronized (mCurrentRequests) {
|
||||
for (Request<?> request : mCurrentRequests) {
|
||||
if (filter.apply(request)) {
|
||||
request.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all requests in this queue with the given tag. Tag must be non-null
|
||||
* and equality is by identity.
|
||||
*/
|
||||
public void cancelAll(final Object tag) {
|
||||
if (tag == null) {
|
||||
throw new IllegalArgumentException("Cannot cancelAll with a null tag");
|
||||
}
|
||||
cancelAll(new RequestFilter() {
|
||||
@Override
|
||||
public boolean apply(Request<?> request) {
|
||||
return request.getTag() == tag;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Request to the dispatch queue.
|
||||
* @param request The request to service
|
||||
* @return The passed-in request
|
||||
*/
|
||||
public <T> Request<T> add(Request<T> request) {
|
||||
// Tag the request as belonging to this queue and add it to the set of current requests.
|
||||
request.setRequestQueue(this);
|
||||
synchronized (mCurrentRequests) {
|
||||
mCurrentRequests.add(request);
|
||||
}
|
||||
|
||||
// Process requests in the order they are added.
|
||||
request.setSequence(getSequenceNumber());
|
||||
request.addMarker("add-to-queue");
|
||||
|
||||
// If the request is uncacheable, skip the cache queue and go straight to the network.
|
||||
if (!request.shouldCache()) {
|
||||
mNetworkQueue.add(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
// Insert request into stage if there's already a request with the same cache key in flight.
|
||||
synchronized (mWaitingRequests) {
|
||||
String cacheKey = request.getCacheKey();
|
||||
if (mWaitingRequests.containsKey(cacheKey)) {
|
||||
// There is already a request in flight. Queue up.
|
||||
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
|
||||
if (stagedRequests == null) {
|
||||
stagedRequests = new LinkedList<Request<?>>();
|
||||
}
|
||||
stagedRequests.add(request);
|
||||
mWaitingRequests.put(cacheKey, stagedRequests);
|
||||
if (VolleyLog.DEBUG) {
|
||||
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
|
||||
}
|
||||
} else {
|
||||
// Insert 'null' queue for this cacheKey, indicating there is now a request in
|
||||
// flight.
|
||||
mWaitingRequests.put(cacheKey, null);
|
||||
mCacheQueue.add(request);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link Request#finish(String)}, indicating that processing of the given request
|
||||
* has finished.
|
||||
*
|
||||
* <p>Releases waiting requests for <code>request.getCacheKey()</code> if
|
||||
* <code>request.shouldCache()</code>.</p>
|
||||
*/
|
||||
<T> void finish(Request<T> request) {
|
||||
// Remove from the set of requests currently being processed.
|
||||
synchronized (mCurrentRequests) {
|
||||
mCurrentRequests.remove(request);
|
||||
}
|
||||
synchronized (mFinishedListeners) {
|
||||
for (RequestFinishedListener<T> listener : mFinishedListeners) {
|
||||
listener.onRequestFinished(request);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.shouldCache()) {
|
||||
synchronized (mWaitingRequests) {
|
||||
String cacheKey = request.getCacheKey();
|
||||
Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
|
||||
if (waitingRequests != null) {
|
||||
if (VolleyLog.DEBUG) {
|
||||
VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
|
||||
waitingRequests.size(), cacheKey);
|
||||
}
|
||||
// Process all queued up requests. They won't be considered as in flight, but
|
||||
// that's not a problem as the cache has been primed by 'request'.
|
||||
mCacheQueue.addAll(waitingRequests);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {
|
||||
synchronized (mFinishedListeners) {
|
||||
mFinishedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a RequestFinishedListener. Has no effect if listener was not previously added.
|
||||
*/
|
||||
public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {
|
||||
synchronized (mFinishedListeners) {
|
||||
mFinishedListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Encapsulates a parsed response for delivery.
|
||||
*
|
||||
* @param <T> Parsed type of this response
|
||||
*/
|
||||
public class Response<T> {
|
||||
|
||||
/** Callback interface for delivering parsed responses. */
|
||||
public interface Listener<T> {
|
||||
/** Called when a response is received. */
|
||||
public void onResponse(T response);
|
||||
}
|
||||
|
||||
/** Callback interface for delivering error responses. */
|
||||
public interface ErrorListener {
|
||||
/**
|
||||
* Callback method that an error has been occurred with the
|
||||
* provided error code and optional user-readable message.
|
||||
*/
|
||||
public void onErrorResponse(VolleyError error);
|
||||
}
|
||||
|
||||
/** Returns a successful response containing the parsed result. */
|
||||
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
|
||||
return new Response<T>(result, cacheEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a failed response containing the given error code and an optional
|
||||
* localized message displayed to the user.
|
||||
*/
|
||||
public static <T> Response<T> error(VolleyError error) {
|
||||
return new Response<T>(error);
|
||||
}
|
||||
|
||||
/** Parsed response, or null in the case of error. */
|
||||
public final T result;
|
||||
|
||||
/** Cache metadata for this response, or null in the case of error. */
|
||||
public final Cache.Entry cacheEntry;
|
||||
|
||||
/** Detailed error information if <code>errorCode != OK</code>. */
|
||||
public final VolleyError error;
|
||||
|
||||
/** True if this response was a soft-expired one and a second one MAY be coming. */
|
||||
public boolean intermediate = false;
|
||||
|
||||
/**
|
||||
* Returns whether this response is considered successful.
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return error == null;
|
||||
}
|
||||
|
||||
|
||||
private Response(T result, Cache.Entry cacheEntry) {
|
||||
this.result = result;
|
||||
this.cacheEntry = cacheEntry;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
private Response(VolleyError error) {
|
||||
this.result = null;
|
||||
this.cacheEntry = null;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
public interface ResponseDelivery {
|
||||
/**
|
||||
* Parses a response from the network or cache and delivers it.
|
||||
*/
|
||||
public void postResponse(Request<?> request, Response<?> response);
|
||||
|
||||
/**
|
||||
* Parses a response from the network or cache and delivers it. The provided
|
||||
* Runnable will be executed after delivery.
|
||||
*/
|
||||
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
|
||||
|
||||
/**
|
||||
* Posts an error for the given request.
|
||||
*/
|
||||
public void postError(Request<?> request, VolleyError error);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Retry policy for a request.
|
||||
*/
|
||||
public interface RetryPolicy {
|
||||
|
||||
/**
|
||||
* Returns the current timeout (used for logging).
|
||||
*/
|
||||
public int getCurrentTimeout();
|
||||
|
||||
/**
|
||||
* Returns the current retry count (used for logging).
|
||||
*/
|
||||
public int getCurrentRetryCount();
|
||||
|
||||
/**
|
||||
* Prepares for the next retry by applying a backoff to the timeout.
|
||||
* @param error The error code of the last attempt.
|
||||
* @throws VolleyError In the event that the retry could not be performed (for example if we
|
||||
* ran out of attempts), the passed in error is thrown.
|
||||
*/
|
||||
public void retry(VolleyError error) throws VolleyError;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Indicates that the server responded with an error response.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ServerError extends VolleyError {
|
||||
public ServerError(NetworkResponse networkResponse) {
|
||||
super(networkResponse);
|
||||
}
|
||||
|
||||
public ServerError() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Indicates that the connection or the socket timed out.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TimeoutError extends VolleyError { }
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
/**
|
||||
* Exception style class encapsulating Volley errors
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class VolleyError extends Exception {
|
||||
public final NetworkResponse networkResponse;
|
||||
private long networkTimeMs;
|
||||
|
||||
public VolleyError() {
|
||||
networkResponse = null;
|
||||
}
|
||||
|
||||
public VolleyError(NetworkResponse response) {
|
||||
networkResponse = response;
|
||||
}
|
||||
|
||||
public VolleyError(String exceptionMessage) {
|
||||
super(exceptionMessage);
|
||||
networkResponse = null;
|
||||
}
|
||||
|
||||
public VolleyError(String exceptionMessage, Throwable reason) {
|
||||
super(exceptionMessage, reason);
|
||||
networkResponse = null;
|
||||
}
|
||||
|
||||
public VolleyError(Throwable cause) {
|
||||
super(cause);
|
||||
networkResponse = null;
|
||||
}
|
||||
|
||||
/* package */ void setNetworkTimeMs(long networkTimeMs) {
|
||||
this.networkTimeMs = networkTimeMs;
|
||||
}
|
||||
|
||||
public long getNetworkTimeMs() {
|
||||
return networkTimeMs;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Logging helper class.
|
||||
* <p/>
|
||||
* to see Volley logs call:<br/>
|
||||
* {@code <android-sdk>/platform-tools/adb shell setprop log.tag.Volley VERBOSE}
|
||||
*/
|
||||
public class VolleyLog {
|
||||
public static String TAG = "Volley";
|
||||
|
||||
public static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
/**
|
||||
* Customize the log tag for your application, so that other apps
|
||||
* using Volley don't mix their logs with yours.
|
||||
* <br />
|
||||
* Enable the log property for your tag before starting your app:
|
||||
* <br />
|
||||
* {@code adb shell setprop log.tag.<tag>}
|
||||
*/
|
||||
public static void setTag(String tag) {
|
||||
d("Changing log tag to %s", tag);
|
||||
TAG = tag;
|
||||
|
||||
// Reinitialize the DEBUG "constant"
|
||||
DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
public static void v(String format, Object... args) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, buildMessage(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String format, Object... args) {
|
||||
Log.d(TAG, buildMessage(format, args));
|
||||
}
|
||||
|
||||
public static void e(String format, Object... args) {
|
||||
Log.e(TAG, buildMessage(format, args));
|
||||
}
|
||||
|
||||
public static void e(Throwable tr, String format, Object... args) {
|
||||
Log.e(TAG, buildMessage(format, args), tr);
|
||||
}
|
||||
|
||||
public static void wtf(String format, Object... args) {
|
||||
Log.wtf(TAG, buildMessage(format, args));
|
||||
}
|
||||
|
||||
public static void wtf(Throwable tr, String format, Object... args) {
|
||||
Log.wtf(TAG, buildMessage(format, args), tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the caller's provided message and prepends useful info like
|
||||
* calling thread ID and method name.
|
||||
*/
|
||||
private static String buildMessage(String format, Object... args) {
|
||||
String msg = (args == null) ? format : String.format(Locale.US, format, args);
|
||||
StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace();
|
||||
|
||||
String caller = "<unknown>";
|
||||
// Walk up the stack looking for the first caller outside of VolleyLog.
|
||||
// It will be at least two frames up, so start there.
|
||||
for (int i = 2; i < trace.length; i++) {
|
||||
Class<?> clazz = trace[i].getClass();
|
||||
if (!clazz.equals(VolleyLog.class)) {
|
||||
String callingClass = trace[i].getClassName();
|
||||
callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1);
|
||||
callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1);
|
||||
|
||||
caller = callingClass + "." + trace[i].getMethodName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return String.format(Locale.US, "[%d] %s: %s",
|
||||
Thread.currentThread().getId(), caller, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple event log with records containing a name, thread ID, and timestamp.
|
||||
*/
|
||||
static class MarkerLog {
|
||||
public static final boolean ENABLED = VolleyLog.DEBUG;
|
||||
|
||||
/** Minimum duration from first marker to last in an marker log to warrant logging. */
|
||||
private static final long MIN_DURATION_FOR_LOGGING_MS = 0;
|
||||
|
||||
private static class Marker {
|
||||
public final String name;
|
||||
public final long thread;
|
||||
public final long time;
|
||||
|
||||
public Marker(String name, long thread, long time) {
|
||||
this.name = name;
|
||||
this.thread = thread;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<Marker> mMarkers = new ArrayList<Marker>();
|
||||
private boolean mFinished = false;
|
||||
|
||||
/** Adds a marker to this log with the specified name. */
|
||||
public synchronized void add(String name, long threadId) {
|
||||
if (mFinished) {
|
||||
throw new IllegalStateException("Marker added to finished log");
|
||||
}
|
||||
|
||||
mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the log, dumping it to logcat if the time difference between
|
||||
* the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}.
|
||||
* @param header Header string to print above the marker log.
|
||||
*/
|
||||
public synchronized void finish(String header) {
|
||||
mFinished = true;
|
||||
|
||||
long duration = getTotalDuration();
|
||||
if (duration <= MIN_DURATION_FOR_LOGGING_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
long prevTime = mMarkers.get(0).time;
|
||||
d("(%-4d ms) %s", duration, header);
|
||||
for (Marker marker : mMarkers) {
|
||||
long thisTime = marker.time;
|
||||
d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name);
|
||||
prevTime = thisTime;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
// Catch requests that have been collected (and hence end-of-lifed)
|
||||
// but had no debugging output printed for them.
|
||||
if (!mFinished) {
|
||||
finish("Request on the loose");
|
||||
e("Marker log finalized without finish() - uncaught exit point for request");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the time difference between the first and last events in this log. */
|
||||
private long getTotalDuration() {
|
||||
if (mMarkers.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long first = mMarkers.get(0).time;
|
||||
long last = mMarkers.get(mMarkers.size() - 1).time;
|
||||
return last - first;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.b44t.messenger.volley.AuthFailureError;
|
||||
import com.b44t.messenger.volley.Cache;
|
||||
import com.b44t.messenger.volley.Cache.Entry;
|
||||
import com.b44t.messenger.volley.Network;
|
||||
import com.b44t.messenger.volley.NetworkError;
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.NoConnectionError;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.RetryPolicy;
|
||||
import com.b44t.messenger.volley.ServerError;
|
||||
import com.b44t.messenger.volley.TimeoutError;
|
||||
import com.b44t.messenger.volley.VolleyError;
|
||||
import com.b44t.messenger.volley.VolleyLog;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.impl.cookie.DateUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A network performing Volley requests over an {@link HttpStack}.
|
||||
*/
|
||||
public class BasicNetwork implements Network {
|
||||
protected static final boolean DEBUG = VolleyLog.DEBUG;
|
||||
|
||||
private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
|
||||
|
||||
private static int DEFAULT_POOL_SIZE = 4096;
|
||||
|
||||
protected final HttpStack mHttpStack;
|
||||
|
||||
protected final ByteArrayPool mPool;
|
||||
|
||||
/**
|
||||
* @param httpStack HTTP stack to be used
|
||||
*/
|
||||
public BasicNetwork(HttpStack httpStack) {
|
||||
// If a pool isn't passed in, then build a small default pool that will give us a lot of
|
||||
// benefit and not use too much memory.
|
||||
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param httpStack HTTP stack to be used
|
||||
* @param pool a buffer pool that improves GC performance in copy operations
|
||||
*/
|
||||
public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
|
||||
mHttpStack = httpStack;
|
||||
mPool = pool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
|
||||
long requestStart = SystemClock.elapsedRealtime();
|
||||
while (true) {
|
||||
HttpResponse httpResponse = null;
|
||||
byte[] responseContents = null;
|
||||
Map<String, String> responseHeaders = Collections.emptyMap();
|
||||
try {
|
||||
// Gather headers.
|
||||
Map<String, String> headers = new HashMap<String, String>();
|
||||
addCacheHeaders(headers, request.getCacheEntry());
|
||||
httpResponse = mHttpStack.performRequest(request, headers);
|
||||
StatusLine statusLine = httpResponse.getStatusLine();
|
||||
int statusCode = statusLine.getStatusCode();
|
||||
|
||||
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
|
||||
// Handle cache validation.
|
||||
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
|
||||
|
||||
Entry entry = request.getCacheEntry();
|
||||
if (entry == null) {
|
||||
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
|
||||
responseHeaders, true,
|
||||
SystemClock.elapsedRealtime() - requestStart);
|
||||
}
|
||||
|
||||
// A HTTP 304 response does not have all header fields. We
|
||||
// have to use the header fields from the cache entry plus
|
||||
// the new ones from the response.
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
|
||||
entry.responseHeaders.putAll(responseHeaders);
|
||||
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
|
||||
entry.responseHeaders, true,
|
||||
SystemClock.elapsedRealtime() - requestStart);
|
||||
}
|
||||
|
||||
// Some responses such as 204s do not have content. We must check.
|
||||
if (httpResponse.getEntity() != null) {
|
||||
responseContents = entityToBytes(httpResponse.getEntity());
|
||||
} else {
|
||||
// Add 0 byte response as a way of honestly representing a
|
||||
// no-content request.
|
||||
responseContents = new byte[0];
|
||||
}
|
||||
|
||||
// if the request is slow, log it.
|
||||
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
|
||||
logSlowRequests(requestLifetime, request, responseContents, statusLine);
|
||||
|
||||
if (statusCode < 200 || statusCode > 299) {
|
||||
throw new IOException();
|
||||
}
|
||||
return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
|
||||
SystemClock.elapsedRealtime() - requestStart);
|
||||
} catch (SocketTimeoutException e) {
|
||||
attemptRetryOnException("socket", request, new TimeoutError());
|
||||
} catch (ConnectTimeoutException e) {
|
||||
attemptRetryOnException("connection", request, new TimeoutError());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException("Bad URL " + request.getUrl(), e);
|
||||
} catch (IOException e) {
|
||||
int statusCode = 0;
|
||||
NetworkResponse networkResponse = null;
|
||||
if (httpResponse != null) {
|
||||
statusCode = httpResponse.getStatusLine().getStatusCode();
|
||||
} else {
|
||||
throw new NoConnectionError(e);
|
||||
}
|
||||
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
|
||||
if (responseContents != null) {
|
||||
networkResponse = new NetworkResponse(statusCode, responseContents,
|
||||
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
|
||||
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
|
||||
statusCode == HttpStatus.SC_FORBIDDEN) {
|
||||
attemptRetryOnException("auth",
|
||||
request, new AuthFailureError(networkResponse));
|
||||
} else {
|
||||
// TODO: Only throw ServerError for 5xx status codes.
|
||||
throw new ServerError(networkResponse);
|
||||
}
|
||||
} else {
|
||||
throw new NetworkError(networkResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
|
||||
*/
|
||||
private void logSlowRequests(long requestLifetime, Request<?> request,
|
||||
byte[] responseContents, StatusLine statusLine) {
|
||||
if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
|
||||
VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
|
||||
"[rc=%d], [retryCount=%s]", request, requestLifetime,
|
||||
responseContents != null ? responseContents.length : "null",
|
||||
statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to prepare the request for a retry. If there are no more attempts remaining in the
|
||||
* request's retry policy, a timeout exception is thrown.
|
||||
* @param request The request to use.
|
||||
*/
|
||||
private static void attemptRetryOnException(String logPrefix, Request<?> request,
|
||||
VolleyError exception) throws VolleyError {
|
||||
RetryPolicy retryPolicy = request.getRetryPolicy();
|
||||
int oldTimeout = request.getTimeoutMs();
|
||||
|
||||
try {
|
||||
retryPolicy.retry(exception);
|
||||
} catch (VolleyError e) {
|
||||
request.addMarker(
|
||||
String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
|
||||
throw e;
|
||||
}
|
||||
request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
|
||||
}
|
||||
|
||||
private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
|
||||
// If there's no cache entry, we're done.
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.etag != null) {
|
||||
headers.put("If-None-Match", entry.etag);
|
||||
}
|
||||
|
||||
if (entry.lastModified > 0) {
|
||||
Date refTime = new Date(entry.lastModified);
|
||||
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
|
||||
}
|
||||
}
|
||||
|
||||
protected void logError(String what, String url, long start) {
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
|
||||
}
|
||||
|
||||
/** Reads the contents of HttpEntity into a byte[]. */
|
||||
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
|
||||
PoolingByteArrayOutputStream bytes =
|
||||
new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
|
||||
byte[] buffer = null;
|
||||
try {
|
||||
InputStream in = entity.getContent();
|
||||
if (in == null) {
|
||||
throw new ServerError();
|
||||
}
|
||||
buffer = mPool.getBuf(1024);
|
||||
int count;
|
||||
while ((count = in.read(buffer)) != -1) {
|
||||
bytes.write(buffer, 0, count);
|
||||
}
|
||||
return bytes.toByteArray();
|
||||
} finally {
|
||||
try {
|
||||
// Close the InputStream and release the resources by "consuming the content".
|
||||
entity.consumeContent();
|
||||
} catch (IOException e) {
|
||||
// This can happen if there was an exception above that left the entity in
|
||||
// an invalid state.
|
||||
VolleyLog.v("Error occured when calling consumingContent");
|
||||
}
|
||||
mPool.returnBuf(buffer);
|
||||
bytes.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Headers[] to Map<String, String>.
|
||||
*/
|
||||
protected static Map<String, String> convertHeaders(Header[] headers) {
|
||||
Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
result.put(headers[i].getName(), headers[i].getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to
|
||||
* supply those buffers to consumers who need to use them for a short period of time and then
|
||||
* dispose of them. Simply creating and disposing such buffers in the conventional manner can
|
||||
* considerable heap churn and garbage collection delays on Android, which lacks good management of
|
||||
* short-lived heap objects. It may be advantageous to trade off some memory in the form of a
|
||||
* permanently allocated pool of buffers in order to gain heap performance improvements; that is
|
||||
* what this class does.
|
||||
* <p>
|
||||
* A good candidate user for this class is something like an I/O system that uses large temporary
|
||||
* <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants
|
||||
* the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks
|
||||
* off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into
|
||||
* account and also to maximize the odds of being able to reuse a recycled buffer, this class is
|
||||
* free to return buffers larger than the requested size. The caller needs to be able to gracefully
|
||||
* deal with getting buffers any size over the minimum.
|
||||
* <p>
|
||||
* If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this
|
||||
* class will allocate a new buffer and return it.
|
||||
* <p>
|
||||
* This class has no special ownership of buffers it creates; the caller is free to take a buffer
|
||||
* it receives from this pool, use it permanently, and never return it to the pool; additionally,
|
||||
* it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there
|
||||
* are no other lingering references to it.
|
||||
* <p>
|
||||
* This class ensures that the total size of the buffers in its recycling pool never exceeds a
|
||||
* certain byte limit. When a buffer is returned that would cause the pool to exceed the limit,
|
||||
* least-recently-used buffers are disposed.
|
||||
*/
|
||||
public class ByteArrayPool {
|
||||
/** The buffer pool, arranged both by last use and by buffer size */
|
||||
private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();
|
||||
private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);
|
||||
|
||||
/** The total size of the buffers in the pool */
|
||||
private int mCurrentSize = 0;
|
||||
|
||||
/**
|
||||
* The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
|
||||
* under this limit.
|
||||
*/
|
||||
private final int mSizeLimit;
|
||||
|
||||
/** Compares buffers by size */
|
||||
protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {
|
||||
@Override
|
||||
public int compare(byte[] lhs, byte[] rhs) {
|
||||
return lhs.length - rhs.length;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param sizeLimit the maximum size of the pool, in bytes
|
||||
*/
|
||||
public ByteArrayPool(int sizeLimit) {
|
||||
mSizeLimit = sizeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a buffer from the pool if one is available in the requested size, or allocates a new
|
||||
* one if a pooled one is not available.
|
||||
*
|
||||
* @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be
|
||||
* larger.
|
||||
* @return a byte[] buffer is always returned.
|
||||
*/
|
||||
public synchronized byte[] getBuf(int len) {
|
||||
for (int i = 0; i < mBuffersBySize.size(); i++) {
|
||||
byte[] buf = mBuffersBySize.get(i);
|
||||
if (buf.length >= len) {
|
||||
mCurrentSize -= buf.length;
|
||||
mBuffersBySize.remove(i);
|
||||
mBuffersByLastUse.remove(buf);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return new byte[len];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
|
||||
* size.
|
||||
*
|
||||
* @param buf the buffer to return to the pool.
|
||||
*/
|
||||
public synchronized void returnBuf(byte[] buf) {
|
||||
if (buf == null || buf.length > mSizeLimit) {
|
||||
return;
|
||||
}
|
||||
mBuffersByLastUse.add(buf);
|
||||
int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
|
||||
if (pos < 0) {
|
||||
pos = -pos - 1;
|
||||
}
|
||||
mBuffersBySize.add(pos, buf);
|
||||
mCurrentSize += buf.length;
|
||||
trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes buffers from the pool until it is under its size limit.
|
||||
*/
|
||||
private synchronized void trim() {
|
||||
while (mCurrentSize > mSizeLimit) {
|
||||
byte[] buf = mBuffersByLastUse.remove(0);
|
||||
mBuffersBySize.remove(buf);
|
||||
mCurrentSize -= buf.length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.Cache;
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* A synthetic request used for clearing the cache.
|
||||
*/
|
||||
public class ClearCacheRequest extends Request<Object> {
|
||||
private final Cache mCache;
|
||||
private final Runnable mCallback;
|
||||
|
||||
/**
|
||||
* Creates a synthetic request for clearing the cache.
|
||||
* @param cache Cache to clear
|
||||
* @param callback Callback to make on the main thread once the cache is clear,
|
||||
* or null for none
|
||||
*/
|
||||
public ClearCacheRequest(Cache cache, Runnable callback) {
|
||||
super(Method.GET, null, null);
|
||||
mCache = cache;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
// This is a little bit of a hack, but hey, why not.
|
||||
mCache.clear();
|
||||
if (mCallback != null) {
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.postAtFrontOfQueue(mCallback);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.IMMEDIATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<Object> parseNetworkResponse(NetworkResponse response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deliverResponse(Object response) {
|
||||
}
|
||||
}
|
||||
@@ -1,571 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.b44t.messenger.volley.Cache;
|
||||
import com.b44t.messenger.volley.VolleyLog;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Cache implementation that caches files directly onto the hard disk in the specified
|
||||
* directory. The default disk usage size is 5MB, but is configurable.
|
||||
*/
|
||||
public class DiskBasedCache implements Cache {
|
||||
|
||||
/** Map of the Key, CacheHeader pairs */
|
||||
private final Map<String, CacheHeader> mEntries =
|
||||
new LinkedHashMap<String, CacheHeader>(16, .75f, true);
|
||||
|
||||
/** Total amount of space currently used by the cache in bytes. */
|
||||
private long mTotalSize = 0;
|
||||
|
||||
/** The root directory to use for the cache. */
|
||||
private final File mRootDirectory;
|
||||
|
||||
/** The maximum size of the cache in bytes. */
|
||||
private final int mMaxCacheSizeInBytes;
|
||||
|
||||
/** Default maximum disk usage in bytes. */
|
||||
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
|
||||
|
||||
/** High water mark percentage for the cache */
|
||||
private static final float HYSTERESIS_FACTOR = 0.9f;
|
||||
|
||||
/** Magic number for current version of cache file format. */
|
||||
private static final int CACHE_MAGIC = 0x20150306;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the DiskBasedCache at the specified directory.
|
||||
* @param rootDirectory The root directory of the cache.
|
||||
* @param maxCacheSizeInBytes The maximum size of the cache in bytes.
|
||||
*/
|
||||
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
|
||||
mRootDirectory = rootDirectory;
|
||||
mMaxCacheSizeInBytes = maxCacheSizeInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the DiskBasedCache at the specified directory using
|
||||
* the default maximum cache size of 5MB.
|
||||
* @param rootDirectory The root directory of the cache.
|
||||
*/
|
||||
public DiskBasedCache(File rootDirectory) {
|
||||
this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cache. Deletes all cached files from disk.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void clear() {
|
||||
File[] files = mRootDirectory.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
mEntries.clear();
|
||||
mTotalSize = 0;
|
||||
VolleyLog.d("Cache cleared.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache entry with the specified key if it exists, null otherwise.
|
||||
*/
|
||||
@Override
|
||||
public synchronized Entry get(String key) {
|
||||
CacheHeader entry = mEntries.get(key);
|
||||
// if the entry does not exist, return.
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = getFileForKey(key);
|
||||
CountingInputStream cis = null;
|
||||
try {
|
||||
cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||
CacheHeader.readHeader(cis); // eat header
|
||||
byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));
|
||||
return entry.toCacheEntry(data);
|
||||
} catch (IOException e) {
|
||||
VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString());
|
||||
remove(key);
|
||||
return null;
|
||||
} finally {
|
||||
if (cis != null) {
|
||||
try {
|
||||
cis.close();
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the DiskBasedCache by scanning for all files currently in the
|
||||
* specified root directory. Creates the root directory if necessary.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void initialize() {
|
||||
if (!mRootDirectory.exists()) {
|
||||
if (!mRootDirectory.mkdirs()) {
|
||||
VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
File[] files = mRootDirectory.listFiles();
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
for (File file : files) {
|
||||
BufferedInputStream fis = null;
|
||||
try {
|
||||
fis = new BufferedInputStream(new FileInputStream(file));
|
||||
CacheHeader entry = CacheHeader.readHeader(fis);
|
||||
entry.size = file.length();
|
||||
putEntry(entry.key, entry);
|
||||
} catch (IOException e) {
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates an entry in the cache.
|
||||
* @param key Cache key
|
||||
* @param fullExpire True to fully expire the entry, false to soft expire
|
||||
*/
|
||||
@Override
|
||||
public synchronized void invalidate(String key, boolean fullExpire) {
|
||||
Entry entry = get(key);
|
||||
if (entry != null) {
|
||||
entry.softTtl = 0;
|
||||
if (fullExpire) {
|
||||
entry.ttl = 0;
|
||||
}
|
||||
put(key, entry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the entry with the specified key into the cache.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void put(String key, Entry entry) {
|
||||
pruneIfNeeded(entry.data.length);
|
||||
File file = getFileForKey(key);
|
||||
try {
|
||||
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
|
||||
CacheHeader e = new CacheHeader(key, entry);
|
||||
boolean success = e.writeHeader(fos);
|
||||
if (!success) {
|
||||
fos.close();
|
||||
VolleyLog.d("Failed to write header for %s", file.getAbsolutePath());
|
||||
throw new IOException();
|
||||
}
|
||||
fos.write(entry.data);
|
||||
fos.close();
|
||||
putEntry(key, e);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
boolean deleted = file.delete();
|
||||
if (!deleted) {
|
||||
VolleyLog.d("Could not clean up file %s", file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified key from the cache if it exists.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void remove(String key) {
|
||||
boolean deleted = getFileForKey(key).delete();
|
||||
removeEntry(key);
|
||||
if (!deleted) {
|
||||
VolleyLog.d("Could not delete cache entry for key=%s, filename=%s",
|
||||
key, getFilenameForKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a pseudo-unique filename for the specified cache key.
|
||||
* @param key The key to generate a file name for.
|
||||
* @return A pseudo-unique filename.
|
||||
*/
|
||||
private String getFilenameForKey(String key) {
|
||||
int firstHalfLength = key.length() / 2;
|
||||
String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode());
|
||||
localFilename += String.valueOf(key.substring(firstHalfLength).hashCode());
|
||||
return localFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file object for the given cache key.
|
||||
*/
|
||||
public File getFileForKey(String key) {
|
||||
return new File(mRootDirectory, getFilenameForKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prunes the cache to fit the amount of bytes specified.
|
||||
* @param neededSpace The amount of bytes we are trying to fit into the cache.
|
||||
*/
|
||||
private void pruneIfNeeded(int neededSpace) {
|
||||
if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) {
|
||||
return;
|
||||
}
|
||||
if (VolleyLog.DEBUG) {
|
||||
VolleyLog.v("Pruning old cache entries.");
|
||||
}
|
||||
|
||||
long before = mTotalSize;
|
||||
int prunedFiles = 0;
|
||||
long startTime = SystemClock.elapsedRealtime();
|
||||
|
||||
Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, CacheHeader> entry = iterator.next();
|
||||
CacheHeader e = entry.getValue();
|
||||
boolean deleted = getFileForKey(e.key).delete();
|
||||
if (deleted) {
|
||||
mTotalSize -= e.size;
|
||||
} else {
|
||||
VolleyLog.d("Could not delete cache entry for key=%s, filename=%s",
|
||||
e.key, getFilenameForKey(e.key));
|
||||
}
|
||||
iterator.remove();
|
||||
prunedFiles++;
|
||||
|
||||
if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (VolleyLog.DEBUG) {
|
||||
VolleyLog.v("pruned %d files, %d bytes, %d ms",
|
||||
prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the entry with the specified key into the cache.
|
||||
* @param key The key to identify the entry by.
|
||||
* @param entry The entry to cache.
|
||||
*/
|
||||
private void putEntry(String key, CacheHeader entry) {
|
||||
if (!mEntries.containsKey(key)) {
|
||||
mTotalSize += entry.size;
|
||||
} else {
|
||||
CacheHeader oldEntry = mEntries.get(key);
|
||||
mTotalSize += (entry.size - oldEntry.size);
|
||||
}
|
||||
mEntries.put(key, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the entry identified by 'key' from the cache.
|
||||
*/
|
||||
private void removeEntry(String key) {
|
||||
CacheHeader entry = mEntries.get(key);
|
||||
if (entry != null) {
|
||||
mTotalSize -= entry.size;
|
||||
mEntries.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of an InputStream into a byte[].
|
||||
* */
|
||||
private static byte[] streamToBytes(InputStream in, int length) throws IOException {
|
||||
byte[] bytes = new byte[length];
|
||||
int count;
|
||||
int pos = 0;
|
||||
while (pos < length && ((count = in.read(bytes, pos, length - pos)) != -1)) {
|
||||
pos += count;
|
||||
}
|
||||
if (pos != length) {
|
||||
throw new IOException("Expected " + length + " bytes, read " + pos + " bytes");
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles holding onto the cache headers for an entry.
|
||||
*/
|
||||
// Visible for testing.
|
||||
static class CacheHeader {
|
||||
/** The size of the data identified by this CacheHeader. (This is not
|
||||
* serialized to disk. */
|
||||
public long size;
|
||||
|
||||
/** The key that identifies the cache entry. */
|
||||
public String key;
|
||||
|
||||
/** ETag for cache coherence. */
|
||||
public String etag;
|
||||
|
||||
/** Date of this response as reported by the server. */
|
||||
public long serverDate;
|
||||
|
||||
/** The last modified date for the requested object. */
|
||||
public long lastModified;
|
||||
|
||||
/** TTL for this record. */
|
||||
public long ttl;
|
||||
|
||||
/** Soft TTL for this record. */
|
||||
public long softTtl;
|
||||
|
||||
/** Headers from the response resulting in this cache entry. */
|
||||
public Map<String, String> responseHeaders;
|
||||
|
||||
private CacheHeader() { }
|
||||
|
||||
/**
|
||||
* Instantiates a new CacheHeader object
|
||||
* @param key The key that identifies the cache entry
|
||||
* @param entry The cache entry.
|
||||
*/
|
||||
public CacheHeader(String key, Entry entry) {
|
||||
this.key = key;
|
||||
this.size = entry.data.length;
|
||||
this.etag = entry.etag;
|
||||
this.serverDate = entry.serverDate;
|
||||
this.lastModified = entry.lastModified;
|
||||
this.ttl = entry.ttl;
|
||||
this.softTtl = entry.softTtl;
|
||||
this.responseHeaders = entry.responseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the header off of an InputStream and returns a CacheHeader object.
|
||||
* @param is The InputStream to read from.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static CacheHeader readHeader(InputStream is) throws IOException {
|
||||
CacheHeader entry = new CacheHeader();
|
||||
int magic = readInt(is);
|
||||
if (magic != CACHE_MAGIC) {
|
||||
// don't bother deleting, it'll get pruned eventually
|
||||
throw new IOException();
|
||||
}
|
||||
entry.key = readString(is);
|
||||
entry.etag = readString(is);
|
||||
if (entry.etag.equals("")) {
|
||||
entry.etag = null;
|
||||
}
|
||||
entry.serverDate = readLong(is);
|
||||
entry.lastModified = readLong(is);
|
||||
entry.ttl = readLong(is);
|
||||
entry.softTtl = readLong(is);
|
||||
entry.responseHeaders = readStringStringMap(is);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache entry for the specified data.
|
||||
*/
|
||||
public Entry toCacheEntry(byte[] data) {
|
||||
Entry e = new Entry();
|
||||
e.data = data;
|
||||
e.etag = etag;
|
||||
e.serverDate = serverDate;
|
||||
e.lastModified = lastModified;
|
||||
e.ttl = ttl;
|
||||
e.softTtl = softTtl;
|
||||
e.responseHeaders = responseHeaders;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the contents of this CacheHeader to the specified OutputStream.
|
||||
*/
|
||||
public boolean writeHeader(OutputStream os) {
|
||||
try {
|
||||
writeInt(os, CACHE_MAGIC);
|
||||
writeString(os, key);
|
||||
writeString(os, etag == null ? "" : etag);
|
||||
writeLong(os, serverDate);
|
||||
writeLong(os, lastModified);
|
||||
writeLong(os, ttl);
|
||||
writeLong(os, softTtl);
|
||||
writeStringStringMap(responseHeaders, os);
|
||||
os.flush();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
VolleyLog.d("%s", e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CountingInputStream extends FilterInputStream {
|
||||
private int bytesRead = 0;
|
||||
|
||||
private CountingInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int result = super.read();
|
||||
if (result != -1) {
|
||||
bytesRead++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
int result = super.read(buffer, offset, count);
|
||||
if (result != -1) {
|
||||
bytesRead += result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Homebrewed simple serialization system used for reading and writing cache
|
||||
* headers on disk. Once upon a time, this used the standard Java
|
||||
* Object{Input,Output}Stream, but the default implementation relies heavily
|
||||
* on reflection (even for standard types) and generates a ton of garbage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple wrapper around {@link InputStream#read()} that throws EOFException
|
||||
* instead of returning -1.
|
||||
*/
|
||||
private static int read(InputStream is) throws IOException {
|
||||
int b = is.read();
|
||||
if (b == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static void writeInt(OutputStream os, int n) throws IOException {
|
||||
os.write((n >> 0) & 0xff);
|
||||
os.write((n >> 8) & 0xff);
|
||||
os.write((n >> 16) & 0xff);
|
||||
os.write((n >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static int readInt(InputStream is) throws IOException {
|
||||
int n = 0;
|
||||
n |= (read(is) << 0);
|
||||
n |= (read(is) << 8);
|
||||
n |= (read(is) << 16);
|
||||
n |= (read(is) << 24);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void writeLong(OutputStream os, long n) throws IOException {
|
||||
os.write((byte)(n >>> 0));
|
||||
os.write((byte)(n >>> 8));
|
||||
os.write((byte)(n >>> 16));
|
||||
os.write((byte)(n >>> 24));
|
||||
os.write((byte)(n >>> 32));
|
||||
os.write((byte)(n >>> 40));
|
||||
os.write((byte)(n >>> 48));
|
||||
os.write((byte)(n >>> 56));
|
||||
}
|
||||
|
||||
static long readLong(InputStream is) throws IOException {
|
||||
long n = 0;
|
||||
n |= ((read(is) & 0xFFL) << 0);
|
||||
n |= ((read(is) & 0xFFL) << 8);
|
||||
n |= ((read(is) & 0xFFL) << 16);
|
||||
n |= ((read(is) & 0xFFL) << 24);
|
||||
n |= ((read(is) & 0xFFL) << 32);
|
||||
n |= ((read(is) & 0xFFL) << 40);
|
||||
n |= ((read(is) & 0xFFL) << 48);
|
||||
n |= ((read(is) & 0xFFL) << 56);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void writeString(OutputStream os, String s) throws IOException {
|
||||
byte[] b = s.getBytes("UTF-8");
|
||||
writeLong(os, b.length);
|
||||
os.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
static String readString(InputStream is) throws IOException {
|
||||
int n = (int) readLong(is);
|
||||
byte[] b = streamToBytes(is, n);
|
||||
return new String(b, "UTF-8");
|
||||
}
|
||||
|
||||
static void writeStringStringMap(Map<String, String> map, OutputStream os) throws IOException {
|
||||
if (map != null) {
|
||||
writeInt(os, map.size());
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
writeString(os, entry.getKey());
|
||||
writeString(os, entry.getValue());
|
||||
}
|
||||
} else {
|
||||
writeInt(os, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, String> readStringStringMap(InputStream is) throws IOException {
|
||||
int size = readInt(is);
|
||||
Map<String, String> result = (size == 0)
|
||||
? Collections.<String, String>emptyMap()
|
||||
: new HashMap<String, String>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
String key = readString(is).intern();
|
||||
String value = readString(is).intern();
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.AuthFailureError;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Request.Method;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.http.client.methods.HttpOptions;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpTrace;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An HttpStack that performs request over an {@link HttpClient}.
|
||||
*/
|
||||
public class HttpClientStack implements HttpStack {
|
||||
protected final HttpClient mClient;
|
||||
|
||||
private final static String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
public HttpClientStack(HttpClient client) {
|
||||
mClient = client;
|
||||
}
|
||||
|
||||
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
|
||||
for (String key : headers.keySet()) {
|
||||
httpRequest.setHeader(key, headers.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {
|
||||
List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size());
|
||||
for (String key : postParams.keySet()) {
|
||||
result.add(new BasicNameValuePair(key, postParams.get(key)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
throws IOException, AuthFailureError {
|
||||
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
|
||||
addHeaders(httpRequest, additionalHeaders);
|
||||
addHeaders(httpRequest, request.getHeaders());
|
||||
onPrepareRequest(httpRequest);
|
||||
HttpParams httpParams = httpRequest.getParams();
|
||||
int timeoutMs = request.getTimeoutMs();
|
||||
// TODO: Reevaluate this connection timeout based on more wide-scale
|
||||
// data collection and possibly different for wifi vs. 3G.
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
|
||||
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
|
||||
return mClient.execute(httpRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the appropriate subclass of HttpUriRequest for passed in request.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
/* protected */ static HttpUriRequest createHttpRequest(Request<?> request,
|
||||
Map<String, String> additionalHeaders) throws AuthFailureError {
|
||||
switch (request.getMethod()) {
|
||||
case Method.DEPRECATED_GET_OR_POST: {
|
||||
// This is the deprecated way that needs to be handled for backwards compatibility.
|
||||
// If the request's post body is null, then the assumption is that the request is
|
||||
// GET. Otherwise, it is assumed that the request is a POST.
|
||||
byte[] postBody = request.getPostBody();
|
||||
if (postBody != null) {
|
||||
HttpPost postRequest = new HttpPost(request.getUrl());
|
||||
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());
|
||||
HttpEntity entity;
|
||||
entity = new ByteArrayEntity(postBody);
|
||||
postRequest.setEntity(entity);
|
||||
return postRequest;
|
||||
} else {
|
||||
return new HttpGet(request.getUrl());
|
||||
}
|
||||
}
|
||||
case Method.GET:
|
||||
return new HttpGet(request.getUrl());
|
||||
case Method.DELETE:
|
||||
return new HttpDelete(request.getUrl());
|
||||
case Method.POST: {
|
||||
HttpPost postRequest = new HttpPost(request.getUrl());
|
||||
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(postRequest, request);
|
||||
return postRequest;
|
||||
}
|
||||
case Method.PUT: {
|
||||
HttpPut putRequest = new HttpPut(request.getUrl());
|
||||
putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(putRequest, request);
|
||||
return putRequest;
|
||||
}
|
||||
case Method.HEAD:
|
||||
return new HttpHead(request.getUrl());
|
||||
case Method.OPTIONS:
|
||||
return new HttpOptions(request.getUrl());
|
||||
case Method.TRACE:
|
||||
return new HttpTrace(request.getUrl());
|
||||
case Method.PATCH: {
|
||||
HttpPatch patchRequest = new HttpPatch(request.getUrl());
|
||||
patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
setEntityIfNonEmptyBody(patchRequest, request);
|
||||
return patchRequest;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException("Unknown request method.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,
|
||||
Request<?> request) throws AuthFailureError {
|
||||
byte[] body = request.getBody();
|
||||
if (body != null) {
|
||||
HttpEntity entity = new ByteArrayEntity(body);
|
||||
httpRequest.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the request is executed using the underlying HttpClient.
|
||||
*
|
||||
* <p>Overwrite in subclasses to augment the request.</p>
|
||||
*/
|
||||
protected void onPrepareRequest(HttpUriRequest request) throws IOException {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* The HttpPatch class does not exist in the Android framework, so this has been defined here.
|
||||
*/
|
||||
public static final class HttpPatch extends HttpEntityEnclosingRequestBase {
|
||||
|
||||
public final static String METHOD_NAME = "PATCH";
|
||||
|
||||
public HttpPatch() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HttpPatch(final URI uri) {
|
||||
super();
|
||||
setURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the uri is invalid.
|
||||
*/
|
||||
public HttpPatch(final String uri) {
|
||||
super();
|
||||
setURI(URI.create(uri));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return METHOD_NAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.Cache;
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
|
||||
import org.apache.http.impl.cookie.DateParseException;
|
||||
import org.apache.http.impl.cookie.DateUtils;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility methods for parsing HTTP headers.
|
||||
*/
|
||||
public class HttpHeaderParser {
|
||||
|
||||
/**
|
||||
* Extracts a {@link Cache.Entry} from a {@link NetworkResponse}.
|
||||
*
|
||||
* @param response The network response to parse headers from
|
||||
* @return a cache entry for the given response, or null if the response is not cacheable.
|
||||
*/
|
||||
public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
Map<String, String> headers = response.headers;
|
||||
|
||||
long serverDate = 0;
|
||||
long lastModified = 0;
|
||||
long serverExpires = 0;
|
||||
long softExpire = 0;
|
||||
long finalExpire = 0;
|
||||
long maxAge = 0;
|
||||
long staleWhileRevalidate = 0;
|
||||
boolean hasCacheControl = false;
|
||||
boolean mustRevalidate = false;
|
||||
|
||||
String serverEtag = null;
|
||||
String headerValue;
|
||||
|
||||
headerValue = headers.get("Date");
|
||||
if (headerValue != null) {
|
||||
serverDate = parseDateAsEpoch(headerValue);
|
||||
}
|
||||
|
||||
headerValue = headers.get("Cache-Control");
|
||||
if (headerValue != null) {
|
||||
hasCacheControl = true;
|
||||
String[] tokens = headerValue.split(",");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String token = tokens[i].trim();
|
||||
if (token.equals("no-cache") || token.equals("no-store")) {
|
||||
return null;
|
||||
} else if (token.startsWith("max-age=")) {
|
||||
try {
|
||||
maxAge = Long.parseLong(token.substring(8));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
} else if (token.startsWith("stale-while-revalidate=")) {
|
||||
try {
|
||||
staleWhileRevalidate = Long.parseLong(token.substring(23));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
|
||||
mustRevalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headerValue = headers.get("Expires");
|
||||
if (headerValue != null) {
|
||||
serverExpires = parseDateAsEpoch(headerValue);
|
||||
}
|
||||
|
||||
headerValue = headers.get("Last-Modified");
|
||||
if (headerValue != null) {
|
||||
lastModified = parseDateAsEpoch(headerValue);
|
||||
}
|
||||
|
||||
serverEtag = headers.get("ETag");
|
||||
|
||||
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
|
||||
// is more restrictive.
|
||||
if (hasCacheControl) {
|
||||
softExpire = now + maxAge * 1000;
|
||||
finalExpire = mustRevalidate
|
||||
? softExpire
|
||||
: softExpire + staleWhileRevalidate * 1000;
|
||||
} else if (serverDate > 0 && serverExpires >= serverDate) {
|
||||
// Default semantic for Expire header in HTTP specification is softExpire.
|
||||
softExpire = now + (serverExpires - serverDate);
|
||||
finalExpire = softExpire;
|
||||
}
|
||||
|
||||
Cache.Entry entry = new Cache.Entry();
|
||||
entry.data = response.data;
|
||||
entry.etag = serverEtag;
|
||||
entry.softTtl = softExpire;
|
||||
entry.ttl = finalExpire;
|
||||
entry.serverDate = serverDate;
|
||||
entry.lastModified = lastModified;
|
||||
entry.responseHeaders = headers;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse date in RFC1123 format, and return its value as epoch
|
||||
*/
|
||||
public static long parseDateAsEpoch(String dateStr) {
|
||||
try {
|
||||
// Parse date in RFC1123 format if this header contains one
|
||||
return DateUtils.parseDate(dateStr).getTime();
|
||||
} catch (DateParseException e) {
|
||||
// Date in invalid format, fallback to 0
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a charset from headers
|
||||
*
|
||||
* @param headers An {@link java.util.Map} of headers
|
||||
* @param defaultCharset Charset to return if none can be found
|
||||
* @return Returns the charset specified in the Content-Type of this header,
|
||||
* or the defaultCharset if none can be found.
|
||||
*/
|
||||
public static String parseCharset(Map<String, String> headers, String defaultCharset) {
|
||||
String contentType = headers.get(HTTP.CONTENT_TYPE);
|
||||
if (contentType != null) {
|
||||
String[] params = contentType.split(";");
|
||||
for (int i = 1; i < params.length; i++) {
|
||||
String[] pair = params[i].trim().split("=");
|
||||
if (pair.length == 2) {
|
||||
if (pair[0].equals("charset")) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaultCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset specified in the Content-Type of this header,
|
||||
* or the HTTP default (ISO-8859-1) if none can be found.
|
||||
*/
|
||||
public static String parseCharset(Map<String, String> headers) {
|
||||
return parseCharset(headers, HTTP.DEFAULT_CONTENT_CHARSET);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.AuthFailureError;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An HTTP stack abstraction.
|
||||
*/
|
||||
public interface HttpStack {
|
||||
/**
|
||||
* Performs an HTTP request with the given parameters.
|
||||
*
|
||||
* <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
|
||||
* and the Content-Type header is set to request.getPostBodyContentType().</p>
|
||||
*
|
||||
* @param request the request to perform
|
||||
* @param additionalHeaders additional headers to be sent together with
|
||||
* {@link Request#getHeaders()}
|
||||
* @return the HTTP response
|
||||
*/
|
||||
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
throws IOException, AuthFailureError;
|
||||
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.AuthFailureError;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Request.Method;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.entity.BasicHttpEntity;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicHttpResponse;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/**
|
||||
* An {@link HttpStack} based on {@link HttpURLConnection}.
|
||||
*/
|
||||
public class HurlStack implements HttpStack {
|
||||
|
||||
private static final String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
/**
|
||||
* An interface for transforming URLs before use.
|
||||
*/
|
||||
public interface UrlRewriter {
|
||||
/**
|
||||
* Returns a URL to use instead of the provided one, or null to indicate
|
||||
* this URL should not be used at all.
|
||||
*/
|
||||
public String rewriteUrl(String originalUrl);
|
||||
}
|
||||
|
||||
private final UrlRewriter mUrlRewriter;
|
||||
private final SSLSocketFactory mSslSocketFactory;
|
||||
|
||||
public HurlStack() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param urlRewriter Rewriter to use for request URLs
|
||||
*/
|
||||
public HurlStack(UrlRewriter urlRewriter) {
|
||||
this(urlRewriter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param urlRewriter Rewriter to use for request URLs
|
||||
* @param sslSocketFactory SSL factory to use for HTTPS connections
|
||||
*/
|
||||
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
|
||||
mUrlRewriter = urlRewriter;
|
||||
mSslSocketFactory = sslSocketFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
throws IOException, AuthFailureError {
|
||||
String url = request.getUrl();
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
map.putAll(request.getHeaders());
|
||||
map.putAll(additionalHeaders);
|
||||
if (mUrlRewriter != null) {
|
||||
String rewritten = mUrlRewriter.rewriteUrl(url);
|
||||
if (rewritten == null) {
|
||||
throw new IOException("URL blocked by rewriter: " + url);
|
||||
}
|
||||
url = rewritten;
|
||||
}
|
||||
URL parsedUrl = new URL(url);
|
||||
HttpURLConnection connection = openConnection(parsedUrl, request);
|
||||
for (String headerName : map.keySet()) {
|
||||
connection.addRequestProperty(headerName, map.get(headerName));
|
||||
}
|
||||
setConnectionParametersForRequest(connection, request);
|
||||
// Initialize HttpResponse with data from the HttpURLConnection.
|
||||
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == -1) {
|
||||
// -1 is returned by getResponseCode() if the response code could not be retrieved.
|
||||
// Signal to the caller that something was wrong with the connection.
|
||||
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
|
||||
}
|
||||
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
|
||||
connection.getResponseCode(), connection.getResponseMessage());
|
||||
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
|
||||
if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
|
||||
response.setEntity(entityFromConnection(connection));
|
||||
}
|
||||
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
|
||||
if (header.getKey() != null) {
|
||||
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
|
||||
response.addHeader(h);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a response message contains a body.
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7230#section-3.3">RFC 7230 section 3.3</a>
|
||||
* @param requestMethod request method
|
||||
* @param responseCode response status code
|
||||
* @return whether the response has a body
|
||||
*/
|
||||
private static boolean hasResponseBody(int requestMethod, int responseCode) {
|
||||
return requestMethod != Request.Method.HEAD
|
||||
&& !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)
|
||||
&& responseCode != HttpStatus.SC_NO_CONTENT
|
||||
&& responseCode != HttpStatus.SC_NOT_MODIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
|
||||
* @param connection
|
||||
* @return an HttpEntity populated with data from <code>connection</code>.
|
||||
*/
|
||||
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
|
||||
BasicHttpEntity entity = new BasicHttpEntity();
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = connection.getInputStream();
|
||||
} catch (IOException ioe) {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
entity.setContent(inputStream);
|
||||
entity.setContentLength(connection.getContentLength());
|
||||
entity.setContentEncoding(connection.getContentEncoding());
|
||||
entity.setContentType(connection.getContentType());
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link HttpURLConnection} for the specified {@code url}.
|
||||
*/
|
||||
protected HttpURLConnection createConnection(URL url) throws IOException {
|
||||
return (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an {@link HttpURLConnection} with parameters.
|
||||
* @param url
|
||||
* @return an open connection
|
||||
* @throws IOException
|
||||
*/
|
||||
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
|
||||
HttpURLConnection connection = createConnection(url);
|
||||
|
||||
int timeoutMs = request.getTimeoutMs();
|
||||
connection.setConnectTimeout(timeoutMs);
|
||||
connection.setReadTimeout(timeoutMs);
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
|
||||
// use caller-provided custom SslSocketFactory, if any, for HTTPS
|
||||
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
|
||||
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
/* package */ static void setConnectionParametersForRequest(HttpURLConnection connection,
|
||||
Request<?> request) throws IOException, AuthFailureError {
|
||||
switch (request.getMethod()) {
|
||||
case Method.DEPRECATED_GET_OR_POST:
|
||||
// This is the deprecated way that needs to be handled for backwards compatibility.
|
||||
// If the request's post body is null, then the assumption is that the request is
|
||||
// GET. Otherwise, it is assumed that the request is a POST.
|
||||
byte[] postBody = request.getPostBody();
|
||||
if (postBody != null) {
|
||||
// Prepare output. There is no need to set Content-Length explicitly,
|
||||
// since this is handled by HttpURLConnection using the size of the prepared
|
||||
// output stream.
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty(HEADER_CONTENT_TYPE,
|
||||
request.getPostBodyContentType());
|
||||
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
|
||||
out.write(postBody);
|
||||
out.close();
|
||||
}
|
||||
break;
|
||||
case Method.GET:
|
||||
// Not necessary to set the request method because connection defaults to GET but
|
||||
// being explicit here.
|
||||
connection.setRequestMethod("GET");
|
||||
break;
|
||||
case Method.DELETE:
|
||||
connection.setRequestMethod("DELETE");
|
||||
break;
|
||||
case Method.POST:
|
||||
connection.setRequestMethod("POST");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Method.PUT:
|
||||
connection.setRequestMethod("PUT");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Method.HEAD:
|
||||
connection.setRequestMethod("HEAD");
|
||||
break;
|
||||
case Method.OPTIONS:
|
||||
connection.setRequestMethod("OPTIONS");
|
||||
break;
|
||||
case Method.TRACE:
|
||||
connection.setRequestMethod("TRACE");
|
||||
break;
|
||||
case Method.PATCH:
|
||||
connection.setRequestMethod("PATCH");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown method type.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
|
||||
throws IOException, AuthFailureError {
|
||||
byte[] body = request.getBody();
|
||||
if (body != null) {
|
||||
connection.setDoOutput(true);
|
||||
connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
|
||||
out.write(body);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.ParseError;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
import com.b44t.messenger.volley.Response.ErrorListener;
|
||||
import com.b44t.messenger.volley.Response.Listener;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A request for retrieving a {@link JSONArray} response body at a given URL.
|
||||
*/
|
||||
public class JsonArrayRequest extends JsonRequest<JSONArray> {
|
||||
|
||||
/**
|
||||
* Creates a new request.
|
||||
* @param url URL to fetch the JSON from
|
||||
* @param listener Listener to receive the JSON response
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {
|
||||
super(Method.GET, url, null, listener, errorListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new request.
|
||||
* @param method the HTTP method to use
|
||||
* @param url URL to fetch the JSON from
|
||||
* @param jsonRequest A {@link JSONArray} to post with the request. Null is allowed and
|
||||
* indicates no parameters will be posted along with request.
|
||||
* @param listener Listener to receive the JSON response
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonArrayRequest(int method, String url, JSONArray jsonRequest,
|
||||
Listener<JSONArray> listener, ErrorListener errorListener) {
|
||||
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
|
||||
errorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
|
||||
try {
|
||||
String jsonString = new String(response.data,
|
||||
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
|
||||
return Response.success(new JSONArray(jsonString),
|
||||
HttpHeaderParser.parseCacheHeaders(response));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return Response.error(new ParseError(e));
|
||||
} catch (JSONException je) {
|
||||
return Response.error(new ParseError(je));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.ParseError;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
import com.b44t.messenger.volley.Response.ErrorListener;
|
||||
import com.b44t.messenger.volley.Response.Listener;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an
|
||||
* optional {@link JSONObject} to be passed in as part of the request body.
|
||||
*/
|
||||
public class JsonObjectRequest extends JsonRequest<JSONObject> {
|
||||
|
||||
/**
|
||||
* Creates a new request.
|
||||
* @param method the HTTP method to use
|
||||
* @param url URL to fetch the JSON from
|
||||
* @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
|
||||
* indicates no parameters will be posted along with request.
|
||||
* @param listener Listener to receive the JSON response
|
||||
* @param errorListener Error listener, or null to ignore errors.
|
||||
*/
|
||||
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
|
||||
Listener<JSONObject> listener, ErrorListener errorListener) {
|
||||
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
|
||||
errorListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
|
||||
* <code>null</code>, <code>POST</code> otherwise.
|
||||
*
|
||||
* @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
|
||||
*/
|
||||
public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
|
||||
ErrorListener errorListener) {
|
||||
this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
|
||||
listener, errorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
|
||||
try {
|
||||
String jsonString = new String(response.data,
|
||||
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
|
||||
return Response.success(new JSONObject(jsonString),
|
||||
HttpHeaderParser.parseCacheHeaders(response));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return Response.error(new ParseError(e));
|
||||
} catch (JSONException je) {
|
||||
return Response.error(new ParseError(je));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
import com.b44t.messenger.volley.Response.ErrorListener;
|
||||
import com.b44t.messenger.volley.Response.Listener;
|
||||
import com.b44t.messenger.volley.VolleyLog;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A request for retrieving a T type response body at a given URL that also
|
||||
* optionally sends along a JSON body in the request specified.
|
||||
*
|
||||
* @param <T> JSON type of response expected
|
||||
*/
|
||||
public abstract class JsonRequest<T> extends Request<T> {
|
||||
/** Default charset for JSON request. */
|
||||
protected static final String PROTOCOL_CHARSET = "utf-8";
|
||||
|
||||
/** Content type for request. */
|
||||
private static final String PROTOCOL_CONTENT_TYPE =
|
||||
String.format("application/json; charset=%s", PROTOCOL_CHARSET);
|
||||
|
||||
private final Listener<T> mListener;
|
||||
private final String mRequestBody;
|
||||
|
||||
/**
|
||||
* Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()}
|
||||
* or {@link #getPostParams()} is overridden (which defaults to POST).
|
||||
*
|
||||
* @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}.
|
||||
*/
|
||||
public JsonRequest(String url, String requestBody, Listener<T> listener,
|
||||
ErrorListener errorListener) {
|
||||
this(Method.DEPRECATED_GET_OR_POST, url, requestBody, listener, errorListener);
|
||||
}
|
||||
|
||||
public JsonRequest(int method, String url, String requestBody, Listener<T> listener,
|
||||
ErrorListener errorListener) {
|
||||
super(method, url, errorListener);
|
||||
mListener = listener;
|
||||
mRequestBody = requestBody;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deliverResponse(T response) {
|
||||
mListener.onResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getBodyContentType()}.
|
||||
*/
|
||||
@Override
|
||||
public String getPostBodyContentType() {
|
||||
return getBodyContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getBody()}.
|
||||
*/
|
||||
@Override
|
||||
public byte[] getPostBody() {
|
||||
return getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBodyContentType() {
|
||||
return PROTOCOL_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() {
|
||||
try {
|
||||
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
|
||||
mRequestBody, PROTOCOL_CHARSET);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.Cache;
|
||||
|
||||
/**
|
||||
* A cache that doesn't.
|
||||
*/
|
||||
public class NoCache implements Cache {
|
||||
@Override
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry get(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, Entry entry) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate(String key, boolean fullExpire) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String key) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
}
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A variation of {@link java.io.ByteArrayOutputStream} that uses a pool of byte[] buffers instead
|
||||
* of always allocating them fresh, saving on heap churn.
|
||||
*/
|
||||
public class PoolingByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
/**
|
||||
* If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is
|
||||
* the default size to which the underlying byte array is initialized.
|
||||
*/
|
||||
private static final int DEFAULT_SIZE = 256;
|
||||
|
||||
private final ByteArrayPool mPool;
|
||||
|
||||
/**
|
||||
* Constructs a new PoolingByteArrayOutputStream with a default size. If more bytes are written
|
||||
* to this instance, the underlying byte array will expand.
|
||||
*/
|
||||
public PoolingByteArrayOutputStream(ByteArrayPool pool) {
|
||||
this(pool, DEFAULT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ByteArrayOutputStream} with a default size of {@code size} bytes. If
|
||||
* more than {@code size} bytes are written to this instance, the underlying byte array will
|
||||
* expand.
|
||||
*
|
||||
* @param size initial size for the underlying byte array. The value will be pinned to a default
|
||||
* minimum size.
|
||||
*/
|
||||
public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) {
|
||||
mPool = pool;
|
||||
buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mPool.returnBuf(buf);
|
||||
buf = null;
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize() {
|
||||
mPool.returnBuf(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures there is enough space in the buffer for the given number of additional bytes.
|
||||
*/
|
||||
private void expand(int i) {
|
||||
/* Can the buffer handle @i more bytes, if not expand it */
|
||||
if (count + i <= buf.length) {
|
||||
return;
|
||||
}
|
||||
byte[] newbuf = mPool.getBuf((count + i) * 2);
|
||||
System.arraycopy(buf, 0, newbuf, 0, count);
|
||||
mPool.returnBuf(buf);
|
||||
buf = newbuf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] buffer, int offset, int len) {
|
||||
expand(len);
|
||||
super.write(buffer, offset, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int oneByte) {
|
||||
expand(1);
|
||||
super.write(oneByte);
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
import com.b44t.messenger.volley.VolleyError;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* A Future that represents a Volley request.
|
||||
*
|
||||
* Used by providing as your response and error listeners. For example:
|
||||
* <pre>
|
||||
* RequestFuture<JSONObject> future = RequestFuture.newFuture();
|
||||
* MyRequest request = new MyRequest(URL, future, future);
|
||||
*
|
||||
* // If you want to be able to cancel the request:
|
||||
* future.setRequest(requestQueue.add(request));
|
||||
*
|
||||
* // Otherwise:
|
||||
* requestQueue.add(request);
|
||||
*
|
||||
* try {
|
||||
* JSONObject response = future.get();
|
||||
* // do something with response
|
||||
* } catch (InterruptedException e) {
|
||||
* // handle the error
|
||||
* } catch (ExecutionException e) {
|
||||
* // handle the error
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> The type of parsed response this future expects.
|
||||
*/
|
||||
public class RequestFuture<T> implements Future<T>, Response.Listener<T>,
|
||||
Response.ErrorListener {
|
||||
private Request<?> mRequest;
|
||||
private boolean mResultReceived = false;
|
||||
private T mResult;
|
||||
private VolleyError mException;
|
||||
|
||||
public static <E> RequestFuture<E> newFuture() {
|
||||
return new RequestFuture<E>();
|
||||
}
|
||||
|
||||
private RequestFuture() {}
|
||||
|
||||
public void setRequest(Request<?> request) {
|
||||
mRequest = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if (mRequest == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDone()) {
|
||||
mRequest.cancel();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
try {
|
||||
return doGet(null);
|
||||
} catch (TimeoutException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit));
|
||||
}
|
||||
|
||||
private synchronized T doGet(Long timeoutMs)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (mException != null) {
|
||||
throw new ExecutionException(mException);
|
||||
}
|
||||
|
||||
if (mResultReceived) {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
if (timeoutMs == null) {
|
||||
wait(0);
|
||||
} else if (timeoutMs > 0) {
|
||||
wait(timeoutMs);
|
||||
}
|
||||
|
||||
if (mException != null) {
|
||||
throw new ExecutionException(mException);
|
||||
}
|
||||
|
||||
if (!mResultReceived) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
|
||||
return mResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
if (mRequest == null) {
|
||||
return false;
|
||||
}
|
||||
return mRequest.isCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isDone() {
|
||||
return mResultReceived || mException != null || isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onResponse(T response) {
|
||||
mResultReceived = true;
|
||||
mResult = response;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onErrorResponse(VolleyError error) {
|
||||
mException = error;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import com.b44t.messenger.volley.NetworkResponse;
|
||||
import com.b44t.messenger.volley.Request;
|
||||
import com.b44t.messenger.volley.Response;
|
||||
import com.b44t.messenger.volley.Response.ErrorListener;
|
||||
import com.b44t.messenger.volley.Response.Listener;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A canned request for retrieving the response body at a given URL as a String.
|
||||
*/
|
||||
public class StringRequest extends Request<String> {
|
||||
private final Listener<String> mListener;
|
||||
|
||||
/**
|
||||
* Creates a new request with the given method.
|
||||
*
|
||||
* @param method the request {@link Method} to use
|
||||
* @param url URL to fetch the string at
|
||||
* @param listener Listener to receive the String response
|
||||
* @param errorListener Error listener, or null to ignore errors
|
||||
*/
|
||||
public StringRequest(int method, String url, Listener<String> listener,
|
||||
ErrorListener errorListener) {
|
||||
super(method, url, errorListener);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GET request.
|
||||
*
|
||||
* @param url URL to fetch the string at
|
||||
* @param listener Listener to receive the String response
|
||||
* @param errorListener Error listener, or null to ignore errors
|
||||
*/
|
||||
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
|
||||
this(Method.GET, url, listener, errorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deliverResponse(String response) {
|
||||
mListener.onResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<String> parseNetworkResponse(NetworkResponse response) {
|
||||
String parsed;
|
||||
try {
|
||||
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
parsed = new String(response.data);
|
||||
}
|
||||
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.b44t.messenger.volley.toolbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.http.AndroidHttpClient;
|
||||
import android.os.Build;
|
||||
|
||||
import com.b44t.messenger.volley.Network;
|
||||
import com.b44t.messenger.volley.RequestQueue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Volley {
|
||||
|
||||
/** Default on-disk cache directory. */
|
||||
private static final String DEFAULT_CACHE_DIR = "volley";
|
||||
|
||||
/**
|
||||
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
|
||||
*
|
||||
* @param context A {@link Context} to use for creating the cache dir.
|
||||
* @param stack An {@link HttpStack} to use for the network, or null for default.
|
||||
* @return A started {@link RequestQueue} instance.
|
||||
*/
|
||||
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
|
||||
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
|
||||
|
||||
String userAgent = "volley/0";
|
||||
try {
|
||||
String packageName = context.getPackageName();
|
||||
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
|
||||
userAgent = packageName + "/" + info.versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
stack = new HurlStack();
|
||||
} else {
|
||||
// Prior to Gingerbread, HttpUrlConnection was unreliable.
|
||||
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
|
||||
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
|
||||
}
|
||||
}
|
||||
|
||||
Network network = new BasicNetwork(stack);
|
||||
|
||||
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
|
||||
queue.start();
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
|
||||
*
|
||||
* @param context A {@link Context} to use for creating the cache dir.
|
||||
* @return A started {@link RequestQueue} instance.
|
||||
*/
|
||||
public static RequestQueue newRequestQueue(Context context) {
|
||||
return newRequestQueue(context, null);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import android.widget.PopupWindow;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
|
||||
@@ -110,7 +109,7 @@ public class ActionBarPopupWindow extends PopupWindow {
|
||||
scrollView.setVerticalScrollBarEnabled(false);
|
||||
addView(scrollView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +320,7 @@ public class ActionBarPopupWindow extends PopupWindow {
|
||||
super.showAsDropDown(anchor, xoff, yoff);
|
||||
registerListener(anchor);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
|
||||
public class BaseFragment {
|
||||
|
||||
@@ -60,7 +59,8 @@ public class BaseFragment {
|
||||
RC13_AVATAR_IMAGE_CAPTURE = 13,
|
||||
RC14_AVATAR_GET_CONTENT = 14,
|
||||
RC21_CHAT_PICK_WO_COMPR = 21,
|
||||
RC500_PHOTO_VIEW = 500;
|
||||
RC500_PHOTO_VIEW = 500,
|
||||
RC600_BATTERY_REQUEST_DONE = 600;
|
||||
|
||||
public BaseFragment() {
|
||||
classGuid = ApplicationLoader.generateClassGuid();
|
||||
@@ -94,7 +94,7 @@ public class BaseFragment {
|
||||
try {
|
||||
parent.removeView(fragmentView);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
fragmentView = null;
|
||||
@@ -105,7 +105,7 @@ public class BaseFragment {
|
||||
try {
|
||||
parent.removeView(actionBar);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
actionBar = null;
|
||||
@@ -122,7 +122,7 @@ public class BaseFragment {
|
||||
try {
|
||||
parent.removeView(fragmentView);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
if (parentLayout != null && parentLayout.getContext() != fragmentView.getContext()) {
|
||||
@@ -135,7 +135,7 @@ public class BaseFragment {
|
||||
try {
|
||||
parent.removeView(actionBar);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
if (parentLayout != null && parentLayout.getContext() != actionBar.getContext()) {
|
||||
@@ -203,7 +203,7 @@ public class BaseFragment {
|
||||
visibleDialog = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public class BaseFragment {
|
||||
visibleDialog = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (actionBar != null) {
|
||||
actionBar.onPause();
|
||||
@@ -308,7 +308,7 @@ public class BaseFragment {
|
||||
visibleDialog = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
try {
|
||||
visibleDialog = dialog;
|
||||
@@ -323,7 +323,7 @@ public class BaseFragment {
|
||||
visibleDialog.show();
|
||||
return visibleDialog;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ import android.widget.TextView;
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.AnimatorListenerAdapterProxy;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
|
||||
@@ -768,7 +767,7 @@ public class BottomSheet extends Dialog {
|
||||
try {
|
||||
BottomSheet.super.dismiss();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -818,7 +817,7 @@ public class BottomSheet extends Dialog {
|
||||
try {
|
||||
dismissInternal();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,7 +44,6 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.AnimatorListenerAdapterProxy;
|
||||
|
||||
@@ -396,7 +395,7 @@ public class DrawerLayoutContainer extends FrameLayout {
|
||||
child.layout(-child.getMeasuredWidth(), lp.topMargin, 0, lp.topMargin + child.getMeasuredHeight());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
inLayout = false;
|
||||
@@ -407,7 +406,7 @@ public class DrawerLayoutContainer extends FrameLayout {
|
||||
if (!inLayout) {
|
||||
/*StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
||||
for (int a = 0; a < elements.length; a++) {
|
||||
FileLog.d("messenger", "on " + elements[a]);
|
||||
Log.d("DeltaChat", "on " + elements[a]);
|
||||
}*/
|
||||
super.requestLayout();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.NotificationCenter;
|
||||
import com.b44t.messenger.Utilities;
|
||||
import com.b44t.messenger.support.widget.RecyclerView;
|
||||
|
||||
@@ -40,10 +40,8 @@ import com.b44t.messenger.MrContact;
|
||||
import com.b44t.messenger.NotificationCenter;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.FileLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.messenger.UserConfig;
|
||||
import com.b44t.messenger.Utilities;
|
||||
import com.b44t.ui.ActionBar.ActionBar;
|
||||
import com.b44t.ui.ActionBar.BaseFragment;
|
||||
@@ -264,7 +262,7 @@ public class AudioSelectActivity extends BaseFragment implements NotificationCen
|
||||
id--;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.view.MotionEvent;
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.MessageObject;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.ui.ActionBar.Theme;
|
||||
|
||||
public class ChatActionCell extends BaseCell {
|
||||
@@ -117,13 +116,13 @@ public class ChatActionCell extends BaseCell {
|
||||
}
|
||||
textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a)));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
return;
|
||||
}
|
||||
textWidth = (int)Math.max(textWidth, Math.ceil(lineWidth));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
textX = (width - textWidth) / 2;
|
||||
|
||||
@@ -51,14 +51,12 @@ import com.b44t.messenger.ImageReceiver;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.MediaController;
|
||||
import com.b44t.messenger.FileLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.MessageObject;
|
||||
import com.b44t.messenger.MrChat;
|
||||
import com.b44t.messenger.MrContact;
|
||||
import com.b44t.messenger.MrMailbox;
|
||||
import com.b44t.messenger.MrPoortext;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.UserObject;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.ui.Components.AvatarDrawable;
|
||||
import com.b44t.ui.Components.LinkPath;
|
||||
@@ -431,7 +429,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
invalidate();
|
||||
return true;
|
||||
@@ -445,7 +443,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else {
|
||||
resetPressedLink(1);
|
||||
@@ -487,14 +485,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
path.setCurrentLayout(captionLayout, start, 0);
|
||||
captionLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), path);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else if (pressedLinkType == 3) {
|
||||
delegate.didPressedUrl(currentMessageObject, pressedLink, false);
|
||||
@@ -912,7 +910,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
String newNameString = null;
|
||||
if (drawName && isGroupChat && !currentMessageObject.isOutOwner()) {
|
||||
if (newUser != null) {
|
||||
newNameString = UserObject.getUserName(newUser);
|
||||
newNameString = "ErrName"; // use MrContact.getName(), if really needed
|
||||
} else if (newChat != null) {
|
||||
newNameString = newChat.title;
|
||||
}
|
||||
@@ -1131,7 +1129,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
if (drawPhotoImage) {
|
||||
@@ -1206,7 +1204,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
invalidate();
|
||||
break;
|
||||
@@ -1569,7 +1567,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1658,7 +1656,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1846,7 +1844,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
try {
|
||||
block.textLayout.draw(canvas);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
@@ -1939,7 +1937,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
try {
|
||||
captionLayout.draw(canvas);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
@@ -1979,7 +1977,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
canvas.restore();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -1990,7 +1988,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
canvas.restore();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2217,7 +2215,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
nameWidth = 0;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (currentNameString.length() == 0) {
|
||||
currentNameString = null;
|
||||
@@ -2251,7 +2249,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
|
||||
forwardNameOffsetX[1] = forwardedNameLayout[1].getLineLeft(0);
|
||||
namesOffset += dp(36);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ import android.view.View;
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.Emoji;
|
||||
import com.b44t.messenger.FileLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.ImageLoader;
|
||||
import com.b44t.messenger.ImageReceiver;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
|
||||
@@ -44,7 +44,6 @@ import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.MessageObject;
|
||||
import com.b44t.messenger.MrChat;
|
||||
import com.b44t.messenger.MrMailbox;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.MrMsg;
|
||||
import com.b44t.messenger.MrPoortext;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
@@ -413,7 +412,7 @@ public class DialogCell extends BaseCell {
|
||||
try {
|
||||
nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
int messageWidth = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline + 16);
|
||||
@@ -467,7 +466,7 @@ public class DialogCell extends BaseCell {
|
||||
try {
|
||||
messageLayout = new StaticLayout(messageStringFinal, currentMessagePaint, messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
|
||||
double widthpx;
|
||||
@@ -650,7 +649,7 @@ public class DialogCell extends BaseCell {
|
||||
try {
|
||||
messageLayout.draw(canvas);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
|
||||
public class DrawerActionCell extends FrameLayout {
|
||||
@@ -61,7 +60,7 @@ public class DrawerActionCell extends FrameLayout {
|
||||
textView.setText(text);
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,7 @@ import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.MrMailbox;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
import com.b44t.ui.ActionBar.Theme;
|
||||
|
||||
@@ -99,7 +97,7 @@ public class DrawerProfileCell extends FrameLayout {
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(mrHeight), MeasureSpec.EXACTLY));
|
||||
} catch (Exception e) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(mrHeight));
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Messenger Android Frontend
|
||||
* (C) 2013-2016 Nikolai Kudashov
|
||||
* (C) 2017 Björn Petersen
|
||||
* Contact: r10s@b44t.com, http://b44t.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see http://www.gnu.org/licenses/ .
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
package com.b44t.ui.Cells;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
|
||||
public class TextColorCell extends FrameLayout {
|
||||
|
||||
private TextView textView;
|
||||
private boolean needDivider;
|
||||
private int currentColor;
|
||||
|
||||
private Drawable colorDrawable;
|
||||
private static Paint paint;
|
||||
|
||||
public TextColorCell(Context context) {
|
||||
super(context);
|
||||
|
||||
if (paint == null) {
|
||||
paint = new Paint();
|
||||
paint.setColor(0xffd9d9d9);
|
||||
paint.setStrokeWidth(1);
|
||||
}
|
||||
|
||||
colorDrawable = getResources().getDrawable(R.drawable.switch_to_on2);
|
||||
|
||||
textView = new TextView(context);
|
||||
textView.setTextColor(0xff212121);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||
textView.setLines(1);
|
||||
textView.setMaxLines(1);
|
||||
textView.setSingleLine(true);
|
||||
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
|
||||
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 17, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
|
||||
}
|
||||
|
||||
public void setTextAndColor(String text, int color, boolean divider) {
|
||||
textView.setText(text);
|
||||
needDivider = divider;
|
||||
currentColor = color;
|
||||
colorDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
|
||||
setWillNotDraw(!needDivider && currentColor == 0);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (needDivider) {
|
||||
canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint);
|
||||
}
|
||||
if (currentColor != 0 && colorDrawable != null) {
|
||||
int x;
|
||||
int y = (getMeasuredHeight() - colorDrawable.getMinimumHeight()) / 2;
|
||||
if (!LocaleController.isRTL) {
|
||||
x = getMeasuredWidth() - colorDrawable.getIntrinsicWidth() - AndroidUtilities.dp(14.5f);
|
||||
} else {
|
||||
x = AndroidUtilities.dp(14.5f);
|
||||
}
|
||||
colorDrawable.setBounds(x, y, x + colorDrawable.getIntrinsicWidth(), y + colorDrawable.getIntrinsicHeight());
|
||||
colorDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,22 +37,31 @@ import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.ui.Components.LayoutHelper;
|
||||
|
||||
import static com.b44t.messenger.AndroidUtilities.dp;
|
||||
|
||||
public class TextSettingsCell extends FrameLayout {
|
||||
|
||||
private TextView textView;
|
||||
private TextView valueTextView;
|
||||
private ImageView valueImageView;
|
||||
private static Paint paint;
|
||||
private boolean valueIsColor;
|
||||
private Paint dividerpaint;
|
||||
private Paint circlepaint;
|
||||
private Paint circleborderpaint;
|
||||
private boolean needDivider;
|
||||
|
||||
public TextSettingsCell(Context context) {
|
||||
super(context);
|
||||
|
||||
if (paint == null) {
|
||||
paint = new Paint();
|
||||
paint.setColor(0xffd9d9d9);
|
||||
paint.setStrokeWidth(1);
|
||||
}
|
||||
dividerpaint = new Paint();
|
||||
dividerpaint.setColor(0xffd9d9d9);
|
||||
dividerpaint.setStrokeWidth(1);
|
||||
|
||||
circleborderpaint = new Paint();
|
||||
circleborderpaint.setColor(0xff000000);
|
||||
circleborderpaint.setStrokeWidth(1);
|
||||
|
||||
circlepaint = new Paint();
|
||||
circlepaint.setAntiAlias(true);
|
||||
|
||||
textView = new TextView(context);
|
||||
textView.setTextColor(0xff212121);
|
||||
@@ -73,27 +82,24 @@ public class TextSettingsCell extends FrameLayout {
|
||||
valueTextView.setEllipsize(TextUtils.TruncateAt.END);
|
||||
valueTextView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL);
|
||||
addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, 17, 0, 17, 0));
|
||||
|
||||
valueImageView = new ImageView(context);
|
||||
valueImageView.setScaleType(ImageView.ScaleType.CENTER);
|
||||
valueImageView.setVisibility(INVISIBLE);
|
||||
addView(valueImageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 17, 0, 17, 0));
|
||||
}
|
||||
|
||||
private final int RADIUS = dp(8);
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(48) + (needDivider ? 1 : 0));
|
||||
|
||||
int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - AndroidUtilities.dp(34);
|
||||
int width = availableWidth / 2;
|
||||
if (valueImageView.getVisibility() == VISIBLE) {
|
||||
valueImageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
|
||||
}
|
||||
if (valueTextView.getVisibility() == VISIBLE) {
|
||||
valueTextView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
|
||||
width = availableWidth - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(8);
|
||||
} else {
|
||||
width = availableWidth;
|
||||
if( valueIsColor ) {
|
||||
width -= RADIUS * 3/*2 for the circle, 1 for space*/;
|
||||
}
|
||||
}
|
||||
textView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
|
||||
}
|
||||
@@ -102,21 +108,16 @@ public class TextSettingsCell extends FrameLayout {
|
||||
textView.setTextColor(color);
|
||||
}
|
||||
|
||||
public void setTextValueColor(int color) {
|
||||
valueTextView.setTextColor(color);
|
||||
}
|
||||
|
||||
public void setText(String text, boolean divider) {
|
||||
textView.setText(text);
|
||||
valueTextView.setVisibility(INVISIBLE);
|
||||
valueImageView.setVisibility(INVISIBLE);
|
||||
needDivider = divider;
|
||||
setWillNotDraw(!divider);
|
||||
}
|
||||
|
||||
public void setTextAndValue(String text, String value, boolean divider) {
|
||||
textView.setText(text);
|
||||
valueImageView.setVisibility(INVISIBLE);
|
||||
valueIsColor = false;
|
||||
if (value != null) {
|
||||
valueTextView.setText(value);
|
||||
valueTextView.setVisibility(VISIBLE);
|
||||
@@ -124,27 +125,31 @@ public class TextSettingsCell extends FrameLayout {
|
||||
valueTextView.setVisibility(INVISIBLE);
|
||||
}
|
||||
needDivider = divider;
|
||||
setWillNotDraw(!divider);
|
||||
setWillNotDraw(!needDivider);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setTextAndIcon(String text, int resId, boolean divider) {
|
||||
public void setTextAndColor(String text, int color, boolean divider) {
|
||||
textView.setText(text);
|
||||
valueIsColor = true;
|
||||
valueTextView.setVisibility(INVISIBLE);
|
||||
if (resId != 0) {
|
||||
valueImageView.setVisibility(VISIBLE);
|
||||
valueImageView.setImageResource(resId);
|
||||
} else {
|
||||
valueImageView.setVisibility(INVISIBLE);
|
||||
}
|
||||
needDivider = divider;
|
||||
setWillNotDraw(!divider);
|
||||
circlepaint.setColor(color);
|
||||
setWillNotDraw(false);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (needDivider) {
|
||||
canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint);
|
||||
canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, dividerpaint);
|
||||
}
|
||||
|
||||
if( valueIsColor ) {
|
||||
int x = getWidth()-getPaddingRight()-dp(17)-RADIUS;
|
||||
int y = getHeight()/2;
|
||||
canvas.drawCircle(x, y, RADIUS+dp(1), circleborderpaint);
|
||||
canvas.drawCircle(x, y, RADIUS, circlepaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ import com.b44t.messenger.support.widget.LinearLayoutManager;
|
||||
import com.b44t.messenger.support.widget.RecyclerView;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.MessageObject;
|
||||
import com.b44t.messenger.NotificationCenter;
|
||||
import com.b44t.messenger.R;
|
||||
@@ -1191,7 +1190,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
}
|
||||
startActivityForResult(takePictureIntent, RC0_CHAT_IMAGE_CAPTURE);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else if (which == ChatAttachAlert.ATTACH_BUTTON_IDX_GALLERY ) {
|
||||
if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -1222,7 +1221,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
|
||||
startActivityForResult(chooserIntent, RC1_CHAT_PICK);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
@@ -1251,7 +1250,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
}
|
||||
startActivityForResult(takeVideoIntent, RC2_CHAT_VIDEO_CAPTURE);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else if (which == ChatAttachAlert.ATTACH_BUTTON_IDX_FILE ) {
|
||||
if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -1274,7 +1273,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
photoPickerIntent.setType("*/*");
|
||||
startActivityForResult(photoPickerIntent, RC21_CHAT_PICK_WO_COMPR);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1366,9 +1365,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); // was: BottomSheet.Builder
|
||||
//builder.setTitle(LocaleController.getString("Notifications", R.string.Notifications)); -- a title seems more confusing than helping -- the user has clicked "mute" before and there are several options all starting with "mute...", I think, this is very clear
|
||||
CharSequence[] items = new CharSequence[]{
|
||||
ApplicationLoader.applicationContext.getString(R.string.MuteFor1Hour),
|
||||
ApplicationLoader.applicationContext.getString(R.string.MuteFor8Hours),
|
||||
ApplicationLoader.applicationContext.getString(R.string.MuteFor2Days),
|
||||
ProfileNotificationsActivity.muteForString( 60*60),
|
||||
ProfileNotificationsActivity.muteForString( 8*60*60),
|
||||
ProfileNotificationsActivity.muteForString(48*60*60),
|
||||
LocaleController.getString("MuteAlways", R.string.MuteAlways)
|
||||
};
|
||||
builder.setItems(items, new DialogInterface.OnClickListener() {
|
||||
@@ -1687,7 +1686,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
arrayList.add(new MediaController.PhotoEntry(0, 0, 0, currentPicturePath, orientation, false));
|
||||
|
||||
@@ -1711,7 +1710,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
try {
|
||||
videoPath = AndroidUtilities.getPath(uri);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (videoPath == null) {
|
||||
showAttachmentError();
|
||||
@@ -1731,7 +1730,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
m_mrChat.cleanDraft(); */
|
||||
} else if (requestCode == RC2_CHAT_VIDEO_CAPTURE) {
|
||||
String videoPath = null;
|
||||
FileLog.d("messenger", "pic path " + currentPicturePath);
|
||||
//Log.i("DeltaChat", "pic path " + currentPicturePath);
|
||||
if (data != null && currentPicturePath != null) {
|
||||
if (new File(currentPicturePath).exists()) {
|
||||
data = null;
|
||||
@@ -1740,9 +1739,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
FileLog.d("messenger", "video record uri " + uri.toString());
|
||||
//Log.i("DeltaChat", "video record uri " + uri.toString());
|
||||
videoPath = AndroidUtilities.getPath(uri);
|
||||
FileLog.d("messenger", "resolved path = " + videoPath);
|
||||
//Log.i("DeltaChat", "resolved path = " + videoPath);
|
||||
if (!(new File(videoPath).exists())) {
|
||||
videoPath = currentPicturePath;
|
||||
}
|
||||
@@ -1787,7 +1786,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
uri = Uri.parse(secondExtraction);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
String tempPath = AndroidUtilities.getPath(uri);
|
||||
|
||||
@@ -39,7 +39,6 @@ import android.os.Looper;
|
||||
import android.view.View;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.FileLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
@@ -142,7 +141,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable {
|
||||
try {
|
||||
backgroundBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
if (backgroundShader == null && backgroundBitmap != null && roundRadius != 0) {
|
||||
backgroundShader = new BitmapShader(backgroundBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
@@ -152,7 +151,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable {
|
||||
getVideoFrame(nativePtr, backgroundBitmap, metaData);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
AndroidUtilities.runOnUIThread(uiRunnable);
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
@@ -183,7 +182,7 @@ public class AvatarDrawable extends Drawable {
|
||||
textHeight = textLayout.getLineBottom(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
} else {
|
||||
textLayout = null;
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.b44t.messenger.ImageLoader;
|
||||
import com.b44t.messenger.MediaController;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.messenger.FileLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.UserConfig;
|
||||
import com.b44t.ui.LaunchActivity;
|
||||
import com.b44t.ui.PhotoAlbumPickerActivity;
|
||||
@@ -85,7 +84,7 @@ public class AvatarUpdater implements PhotoCropActivity.PhotoEditActivityDelegat
|
||||
}
|
||||
parentFragment.startActivityForResult(takePictureIntent, BaseFragment.RC13_AVATAR_IMAGE_CAPTURE);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +113,7 @@ public class AvatarUpdater implements PhotoCropActivity.PhotoEditActivityDelegat
|
||||
photoPickerIntent.setType("image/*");
|
||||
parentFragment.startActivityForResult(photoPickerIntent, BaseFragment.RC14_AVATAR_GET_CONTENT);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
@@ -142,7 +141,7 @@ public class AvatarUpdater implements PhotoCropActivity.PhotoEditActivityDelegat
|
||||
photoCropActivity.setDelegate(this);
|
||||
activity.presentFragment(photoCropActivity);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
Bitmap bitmap = ImageLoader.loadBitmap(path, uri, 800, 800, true);
|
||||
processBitmap(bitmap);
|
||||
}
|
||||
@@ -168,7 +167,7 @@ public class AvatarUpdater implements PhotoCropActivity.PhotoEditActivityDelegat
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
final ArrayList<Object> arrayList = new ArrayList<>();
|
||||
arrayList.add(new MediaController.PhotoEntry(0, 0, 0, currentPicturePath, orientation, false));
|
||||
|
||||
@@ -68,11 +68,9 @@ import com.b44t.messenger.MessageObject;
|
||||
import com.b44t.messenger.MrContact;
|
||||
import com.b44t.messenger.MrMailbox;
|
||||
import com.b44t.messenger.SendMessagesHelper;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.NotificationCenter;
|
||||
import com.b44t.messenger.R;
|
||||
import com.b44t.messenger.TLRPC;
|
||||
import com.b44t.messenger.UserConfig;
|
||||
import com.b44t.messenger.AnimatorListenerAdapterProxy;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.ui.ActionBar.Theme;
|
||||
@@ -82,7 +80,7 @@ import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChatActivityEnterView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, StickersAlert.StickersAlertDelegate {
|
||||
public class ChatActivityEnterView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate /*, StickersAlert.StickersAlertDelegate*/ {
|
||||
|
||||
public interface ChatActivityEnterViewDelegate {
|
||||
void onMessageSend(CharSequence message);
|
||||
@@ -181,7 +179,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
} catch (Exception e) {
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(51));
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +217,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
try {
|
||||
return super.onTouchEvent(event);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -860,7 +858,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
mWakeLock.release();
|
||||
mWakeLock = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
if (sizeNotifierLayout != null) {
|
||||
@@ -1158,7 +1156,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
mWakeLock.acquire();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
AndroidUtilities.lockOrientation(parentActivity);
|
||||
|
||||
@@ -1200,7 +1198,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
mWakeLock.release();
|
||||
mWakeLock = null;
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
AndroidUtilities.unlockOrientation(parentActivity);
|
||||
@@ -1274,7 +1272,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
messageEditText.setText(builder);
|
||||
messageEditText.setSelection(start + text.length());
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,7 +1289,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
try {
|
||||
messageEditText.requestFocus();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1364,15 +1362,15 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
int j = i + localCharSequence.length();
|
||||
messageEditText.setSelection(j, j);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
} finally {
|
||||
innerTextChange = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void onStickerSelected(TLRPC.Document sticker) {
|
||||
/*public void onStickerSelected(TLRPC.Document sticker) {
|
||||
ChatActivityEnterView.this.onStickerSelected(sticker);
|
||||
}
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onStickersSettingsClick() {
|
||||
@@ -1432,13 +1430,13 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
||||
sizeNotifierLayout.addView(emojiView);
|
||||
}
|
||||
|
||||
@Override
|
||||
/*@Override
|
||||
public void onStickerSelected(TLRPC.Document sticker) {
|
||||
SendMessagesHelper.getInstance().sendSticker(sticker, dialog_id);
|
||||
if (delegate != null) {
|
||||
delegate.onMessageSend(null);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
private void showPopup(int show, int contentType /*0=emojiView, 1=botKeyboardView*/ ) {
|
||||
if (show == 1) {
|
||||
|
||||
@@ -49,7 +49,6 @@ import android.widget.TextView;
|
||||
|
||||
import com.b44t.messenger.AndroidUtilities;
|
||||
import com.b44t.messenger.ApplicationLoader;
|
||||
import com.b44t.messenger.FileLog;
|
||||
import com.b44t.messenger.LocaleController;
|
||||
import com.b44t.messenger.MediaController;
|
||||
import com.b44t.messenger.MessageObject;
|
||||
@@ -832,7 +831,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N
|
||||
try {
|
||||
animators.add(ViewAnimationUtils.createCircularReveal(containerView, finalRevealX, revealY, open ? 0 : finalRevealRadius, open ? finalRevealRadius : 0));
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
animatorSet.setDuration(320);
|
||||
} else {
|
||||
@@ -866,7 +865,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N
|
||||
try {
|
||||
dismissInternal();
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.view.View;
|
||||
|
||||
import com.b44t.messenger.FileLog;
|
||||
|
||||
public class ClippingImageView extends View {
|
||||
|
||||
private int clipBottom;
|
||||
@@ -173,7 +171,7 @@ public class ClippingImageView extends View {
|
||||
try {
|
||||
canvas.drawBitmap(bmp, matrix, paint);
|
||||
} catch (Exception e) {
|
||||
FileLog.e("messenger", e);
|
||||
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ColorPickerView extends View {
|
||||
private static final String STATE_PARENT = "parent";
|
||||
private static final String STATE_ANGLE = "angle";
|
||||
private static final String STATE_OLD_COLOR = "color";
|
||||
private static final String STATE_SHOW_OLD_COLOR = "showColor";
|
||||
//private static final String STATE_SHOW_OLD_COLOR = "showColor";
|
||||
|
||||
private static final int[] COLORS = new int[] { 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 0xFFFFFFFF, 0xFFFFFF00, 0xFFFF0000 };
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ColorPickerView extends View {
|
||||
private RectF mCenterRectangle = new RectF();
|
||||
private boolean mUserIsMovingPointer = false;
|
||||
private int mCenterOldColor;
|
||||
private boolean mShowCenterOldColor;
|
||||
private final boolean mShowCenterOldColor = false;
|
||||
private int mCenterNewColor;
|
||||
private float mTranslationOffset;
|
||||
private float mSlopX;
|
||||
@@ -145,7 +145,7 @@ public class ColorPickerView extends View {
|
||||
|
||||
mCenterNewColor = calculateColor(mAngle);
|
||||
mCenterOldColor = calculateColor(mAngle);
|
||||
mShowCenterOldColor = true;
|
||||
//mShowCenterOldColor = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -344,14 +344,14 @@ public class ColorPickerView extends View {
|
||||
return mCenterOldColor;
|
||||
}
|
||||
|
||||
public void setShowOldCenterColor(boolean show) {
|
||||
/*public void setShowOldCenterColor(boolean show) {
|
||||
mShowCenterOldColor = show;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public boolean getShowOldCenterColor() {
|
||||
return mShowCenterOldColor;
|
||||
}
|
||||
}*/
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
@@ -361,7 +361,7 @@ public class ColorPickerView extends View {
|
||||
state.putParcelable(STATE_PARENT, superState);
|
||||
state.putFloat(STATE_ANGLE, mAngle);
|
||||
state.putInt(STATE_OLD_COLOR, mCenterOldColor);
|
||||
state.putBoolean(STATE_SHOW_OLD_COLOR, mShowCenterOldColor);
|
||||
//state.putBoolean(STATE_SHOW_OLD_COLOR, mShowCenterOldColor);
|
||||
|
||||
return state;
|
||||
}
|
||||
@@ -375,7 +375,7 @@ public class ColorPickerView extends View {
|
||||
|
||||
mAngle = savedState.getFloat(STATE_ANGLE);
|
||||
setOldCenterColor(savedState.getInt(STATE_OLD_COLOR));
|
||||
mShowCenterOldColor = savedState.getBoolean(STATE_SHOW_OLD_COLOR);
|
||||
//mShowCenterOldColor = savedState.getBoolean(STATE_SHOW_OLD_COLOR);
|
||||
int currentColor = calculateColor(mAngle);
|
||||
mPointerColor.setColor(currentColor);
|
||||
setNewCenterColor(currentColor);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user