update to 11.5.3 (5511)

This commit is contained in:
dkaraush 2024-12-06 21:05:26 +04:00
parent fb2e545101
commit 9dcd88b8c1
177 changed files with 12835 additions and 2552 deletions

View file

@ -917,6 +917,8 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Stories_recorder_FfmpegAudioWaveform
int skip = 4;
int barWidth = (int) round((double) duration_in_seconds * sampleRate / count / (1 + skip)); // Assuming you have 'duration' and 'count' defined somewhere
int channels = codecContext->channels;
short peak = 0;
int currentCount = 0;
int index = 0;
@ -937,9 +939,43 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Stories_recorder_FfmpegAudioWaveform
break;
}
int16_t* samples = (int16_t*) frame->data[0];
const int is_planar = av_sample_fmt_is_planar(codecContext->sample_fmt);
const int sample_size = av_get_bytes_per_sample(codecContext->sample_fmt);
for (int i = 0; i < frame->nb_samples; i++) {
short value = samples[i]; // Read the 16-bit PCM sample
int sum = 0;
for (int channel = 0; channel < channels; channel++) {
uint8_t *data;
if (is_planar) {
data = frame->data[channel] + i * sample_size;
} else {
data = frame->data[0] + (i * channels + channel) * sample_size;
}
short sample_value = 0;
switch (codecContext->sample_fmt) {
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
// Signed 16-bit PCM
sample_value = *(int16_t *)data;
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
// 32-bit float, scale to 16-bit PCM range
sample_value = (short)(*(float *)data * 32767.0f);
break;
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
// Unsigned 8-bit PCM, scale to 16-bit PCM range
sample_value = (*(uint8_t *)data - 128) * 256;
break;
default:
break;
}
sum += sample_value;
}
short value = sum / channels;
if (currentCount >= barWidth) {
waveformChunkData[index - chunkIndex] = peak;

View file

@ -176,7 +176,7 @@ int open_codec_context(int *stream_idx, AVCodecContext **dec_ctx, AVFormatContex
dec = avcodec_find_decoder(st->codecpar->codec_id);
if (!dec) {
LOGE("failed to find %s codec", av_get_media_type_string(type));
LOGE("failed to find %d codec", st->codecpar->codec_id);
return AVERROR(EINVAL);
}
@ -857,7 +857,7 @@ extern "C" JNIEXPORT int JNICALL Java_org_telegram_ui_Components_AnimatedFileDra
}
extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview, jfloat start_time, jfloat end_time, jboolean loop) {
if (ptr == NULL || bitmap == nullptr) {
if (ptr == NULL) {
return 0;
}
//int64_t time = ConnectionsManager::getInstance(0).getCurrentTimeMonotonicMillis();
@ -946,10 +946,11 @@ extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
}
if (got_frame) {
//LOGD("decoded frame with w = %d, h = %d, format = %d", info->frame->width, info->frame->height, info->frame->format);
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P || info->frame->format == AV_PIX_FMT_YUV444P || info->frame->format == AV_PIX_FMT_YUVA420P) {
if (bitmap != nullptr && (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P || info->frame->format == AV_PIX_FMT_YUV444P || info->frame->format == AV_PIX_FMT_YUVA420P)) {
writeFrameToBitmap(env, info, data, bitmap, stride);
}
info->has_decoded_frames = true;
push_time(env, info, data);
av_frame_unref(info->frame);
return 1;
}

Binary file not shown.

View file

@ -20,6 +20,7 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context;
import android.media.MediaCodec;
import android.media.PlaybackParams;
import android.opengl.EGLContext;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.IntDef;
@ -286,6 +287,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
@Override
public Renderer[] createRenderers(
Handler eventHandler,
EGLContext parentContext,
VideoRendererEventListener videoRendererEventListener,
AudioRendererEventListener audioRendererEventListener,
TextOutput textRendererOutput,
@ -293,6 +295,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
ArrayList<Renderer> renderersList = new ArrayList<>();
buildVideoRenderers(
context,
parentContext,
extensionRendererMode,
mediaCodecSelector,
enableDecoderFallback,
@ -348,6 +351,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
*/
protected void buildVideoRenderers(
Context context,
EGLContext parentContext,
@ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback,
@ -358,6 +362,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
MediaCodecVideoRenderer videoRenderer =
new MediaCodecVideoRenderer(
context,
parentContext,
getCodecAdapterFactory(),
mediaCodecSelector,
allowedVideoJoiningTimeMs,

View file

@ -23,6 +23,7 @@ import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.opengl.EGLContext;
import android.os.Looper;
import android.os.Process;
import android.view.Surface;
@ -452,6 +453,7 @@ public interface ExoPlayer extends Player {
final class Builder {
/* package */ final Context context;
public EGLContext eglContext;
/* package */ Clock clock;
/* package */ long foregroundModeTimeoutMs;

View file

@ -249,6 +249,7 @@ import java.util.concurrent.TimeoutException;
.get()
.createRenderers(
eventHandler,
builder.eglContext,
componentListener,
componentListener,
componentListener,

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2;
import android.opengl.EGLContext;
import android.os.Handler;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.metadata.MetadataOutput;
@ -36,6 +37,7 @@ public interface RenderersFactory {
*/
Renderer[] createRenderers(
Handler eventHandler,
EGLContext parentContext,
VideoRendererEventListener videoRendererEventListener,
AudioRendererEventListener audioRendererEventListener,
TextOutput textRendererOutput,

View file

@ -28,6 +28,7 @@ import android.media.AudioFormat;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.opengl.EGLContext;
import android.os.Handler;
import androidx.annotation.CallSuper;
import androidx.annotation.DoNotInline;
@ -418,7 +419,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
MediaCodecInfo codecInfo,
Format format,
@Nullable MediaCrypto crypto,
float codecOperatingRate) {
float codecOperatingRate,
EGLContext parentContext
) {
codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats());
codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name);
MediaFormat mediaFormat =

View file

@ -39,6 +39,7 @@ import android.media.MediaCrypto;
import android.media.MediaCryptoException;
import android.media.MediaFormat;
import android.media.metrics.LogSessionId;
import android.opengl.EGLContext;
import android.os.Bundle;
import android.os.SystemClock;
import androidx.annotation.CallSuper;
@ -75,6 +76,8 @@ import com.google.android.exoplayer2.util.NalUnitUtil;
import com.google.android.exoplayer2.util.TimedValueQueue;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -487,7 +490,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
MediaCodecInfo codecInfo,
Format format,
@Nullable MediaCrypto crypto,
float codecOperatingRate);
float codecOperatingRate,
EGLContext context);
protected final void maybeInitCodecOrBypass() throws ExoPlaybackException {
if (codec != null || bypassEnabled || inputFormat == null) {
@ -1099,7 +1103,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
codecInitializingTimestamp = SystemClock.elapsedRealtime();
MediaCodecAdapter.Configuration configuration =
getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate);
getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate, this instanceof MediaCodecVideoRenderer ? ((MediaCodecVideoRenderer) this).eglContext : null);
if (Util.SDK_INT >= 31) {
Api31.setLogSessionIdToMediaCodecFormat(configuration, getPlayerId());
}

View file

@ -152,6 +152,7 @@ public final class DownloadHelper {
Renderer[] renderers =
renderersFactory.createRenderers(
Util.createHandlerForCurrentOrMainLooper(),
null,
new VideoRendererEventListener() {},
new AudioRendererEventListener() {},
(cues) -> {},

View file

@ -292,7 +292,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
private @C.NetworkType int networkType;
private long totalElapsedTimeMs;
private long totalBytesTransferred;
private long bitrateEstimate;
private volatile long bitrateEstimate;
private long lastReportedBitrateEstimate;
private boolean networkTypeOverrideSet;
@ -420,7 +420,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
streamCount--;
}
public void onTransfer(long bytes, long duration) {
public synchronized void onTransfer(long bytes, long duration) {
long nowMs = clock.elapsedRealtime();
int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs);
totalElapsedTimeMs += sampleElapsedTimeMs;

View file

@ -90,7 +90,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
/**
* @param handler The {@link Handler} that will be used to call {@link
* SurfaceTexture#updateTexImage()} to update images on the {@link SurfaceTexture}. Note that
* {@link #init(int)} has to be called on the same looper thread as the {@link Handler}'s
* {@link #init(int, EGLContext)} has to be called on the same looper thread as the {@link Handler}'s
* looper.
*/
public EGLSurfaceTexture(Handler handler) {
@ -100,7 +100,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
/**
* @param handler The {@link Handler} that will be used to call {@link
* SurfaceTexture#updateTexImage()} to update images on the {@link SurfaceTexture}. Note that
* {@link #init(int)} has to be called on the same looper thread as the looper of the {@link
* {@link #init(int, EGLContext)} has to be called on the same looper thread as the looper of the {@link
* Handler}.
* @param callback The {@link TextureImageListener} to be called when the texture image on {@link
* SurfaceTexture} has been updated. This callback will be called on the same handler thread
@ -117,10 +117,10 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
*
* @param secureMode The {@link SecureMode} to be used for EGL surface.
*/
public void init(@SecureMode int secureMode) throws GlUtil.GlException {
public void init(@SecureMode int secureMode, EGLContext parentContext) throws GlUtil.GlException {
display = getDefaultDisplay();
EGLConfig config = chooseEGLConfig(display);
context = createEGLContext(display, config, secureMode);
context = createEGLContext(display, config, secureMode, parentContext);
surface = createEGLSurface(display, config, context, secureMode);
generateTextureIds(textureIdHolder);
texture = new SurfaceTexture(textureIdHolder[0]);
@ -164,7 +164,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
}
/**
* Returns the wrapped {@link SurfaceTexture}. This can only be called after {@link #init(int)}.
* Returns the wrapped {@link SurfaceTexture}. This can only be called after {@link #init(int, EGLContext)}.
*/
public SurfaceTexture getSurfaceTexture() {
return Assertions.checkNotNull(texture);
@ -232,7 +232,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
}
private static EGLContext createEGLContext(
EGLDisplay display, EGLConfig config, @SecureMode int secureMode) throws GlUtil.GlException {
EGLDisplay display, EGLConfig config, @SecureMode int secureMode, EGLContext eglContext) throws GlUtil.GlException {
int[] glAttributes;
if (secureMode == SECURE_MODE_NONE) {
glAttributes = new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
@ -248,7 +248,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
}
EGLContext context =
EGL14.eglCreateContext(
display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes, 0);
display, config, eglContext == null ? android.opengl.EGL14.EGL_NO_CONTEXT : eglContext, glAttributes, 0);
GlUtil.checkGlException(context != null, "eglCreateContext failed");
return context;
}

View file

@ -34,6 +34,7 @@ import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.opengl.EGLContext;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -123,6 +124,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
private final Context context;
public EGLContext eglContext;
private final VideoFrameReleaseHelper frameReleaseHelper;
private final EventDispatcher eventDispatcher;
private final long allowedJoiningTimeMs;
@ -207,6 +209,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
int maxDroppedFramesToNotify) {
this(
context,
null,
MediaCodecAdapter.Factory.DEFAULT,
mediaCodecSelector,
allowedJoiningTimeMs,
@ -241,6 +244,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
int maxDroppedFramesToNotify) {
this(
context,
null,
MediaCodecAdapter.Factory.DEFAULT,
mediaCodecSelector,
allowedJoiningTimeMs,
@ -269,6 +273,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
*/
public MediaCodecVideoRenderer(
Context context,
EGLContext parentContext,
MediaCodecAdapter.Factory codecAdapterFactory,
MediaCodecSelector mediaCodecSelector,
long allowedJoiningTimeMs,
@ -279,6 +284,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
this(
context,
parentContext,
codecAdapterFactory,
mediaCodecSelector,
allowedJoiningTimeMs,
@ -312,6 +318,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
*/
public MediaCodecVideoRenderer(
Context context,
EGLContext parentContext,
MediaCodecAdapter.Factory codecAdapterFactory,
MediaCodecSelector mediaCodecSelector,
long allowedJoiningTimeMs,
@ -329,6 +336,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
this.context = context.getApplicationContext();
this.eglContext = parentContext;
frameReleaseHelper = new VideoFrameReleaseHelper(this.context);
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
@ -674,7 +682,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} else {
MediaCodecInfo codecInfo = getCodecInfo();
if (codecInfo != null && shouldUsePlaceholderSurface(codecInfo)) {
placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure);
placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure, eglContext);
surface = placeholderSurface;
}
}
@ -739,8 +747,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
MediaCodecInfo codecInfo,
Format format,
@Nullable MediaCrypto crypto,
float codecOperatingRate) {
if (placeholderSurface != null && placeholderSurface.secure != codecInfo.secure) {
float codecOperatingRate,
EGLContext parentContext
) {
if (placeholderSurface != null && (placeholderSurface.secure != codecInfo.secure || placeholderSurface.parentContext != parentContext)) {
// We can't re-use the current DummySurface instance with the new decoder.
releasePlaceholderSurface();
}
@ -759,7 +769,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
throw new IllegalStateException();
}
if (placeholderSurface == null) {
placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure);
placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure, parentContext);
}
surface = placeholderSurface;
}

View file

@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.util.EGLSurfaceTexture.SECURE_MODE_S
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.EGLContext;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@ -43,6 +44,7 @@ public final class PlaceholderSurface extends Surface {
/** Whether the surface is secure. */
public final boolean secure;
public final EGLContext parentContext;
private static @SecureMode int secureMode;
private static boolean secureModeInitialized;
@ -76,17 +78,18 @@ public final class PlaceholderSurface extends Surface {
* @throws IllegalStateException If a secure surface is requested on a device for which {@link
* #isSecureSupported(Context)} returns {@code false}.
*/
public static PlaceholderSurface newInstanceV17(Context context, boolean secure) {
public static PlaceholderSurface newInstanceV17(Context context, boolean secure, EGLContext parentContext) {
Assertions.checkState(!secure || isSecureSupported(context));
PlaceholderSurfaceThread thread = new PlaceholderSurfaceThread();
return thread.init(secure ? secureMode : SECURE_MODE_NONE);
return thread.init(secure ? secureMode : SECURE_MODE_NONE, parentContext);
}
private PlaceholderSurface(
PlaceholderSurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) {
PlaceholderSurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure, EGLContext parentContext) {
super(surfaceTexture);
this.thread = thread;
this.secure = secure;
this.parentContext = parentContext;
}
@Override
@ -135,13 +138,13 @@ public final class PlaceholderSurface extends Surface {
super("ExoPlayer:PlaceholderSurface");
}
public PlaceholderSurface init(@SecureMode int secureMode) {
public PlaceholderSurface init(@SecureMode int secureMode, EGLContext parentContext) {
start();
handler = new Handler(getLooper(), /* callback= */ this);
eglSurfaceTexture = new EGLSurfaceTexture(handler);
boolean wasInterrupted = false;
synchronized (this) {
handler.obtainMessage(MSG_INIT, secureMode, 0).sendToTarget();
handler.obtainMessage(MSG_INIT, secureMode, 0, parentContext).sendToTarget();
while (surface == null && initException == null && initError == null) {
try {
wait();
@ -173,7 +176,7 @@ public final class PlaceholderSurface extends Surface {
switch (msg.what) {
case MSG_INIT:
try {
initInternal(/* secureMode= */ msg.arg1);
initInternal(/* secureMode= */ msg.arg1, msg.obj == null ? null : (EGLContext) msg.obj);
} catch (RuntimeException e) {
Log.e(TAG, "Failed to initialize placeholder surface", e);
initException = e;
@ -203,12 +206,12 @@ public final class PlaceholderSurface extends Surface {
}
}
private void initInternal(@SecureMode int secureMode) throws GlUtil.GlException {
private void initInternal(@SecureMode int secureMode, EGLContext parentContext) throws GlUtil.GlException {
Assertions.checkNotNull(eglSurfaceTexture);
eglSurfaceTexture.init(secureMode);
eglSurfaceTexture.init(secureMode, parentContext);
this.surface =
new PlaceholderSurface(
this, eglSurfaceTexture.getSurfaceTexture(), secureMode != SECURE_MODE_NONE);
this, eglSurfaceTexture.getSurfaceTexture(), secureMode != SECURE_MODE_NONE, parentContext);
}
private void releaseInternal() {

View file

@ -4881,6 +4881,10 @@ public class AndroidUtilities {
return -1;
}
public static float distance(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
public static int lerp(int a, int b, float f) {
return (int) (a + f * (b - a));
}
@ -5861,6 +5865,10 @@ public class AndroidUtilities {
return Math.max(x1, x2) > Math.min(y1, y2) && Math.max(y1, y2) > Math.min(x1, x2);
}
public static boolean intersect1d(float x1, float x2, float y1, float y2) {
return Math.max(x1, x2) > Math.min(y1, y2) && Math.max(y1, y2) > Math.min(x1, x2);
}
public static boolean intersect1dInclusive(int x1, int x2, int y1, int y2) {
return Math.max(x1, x2) >= Math.min(y1, y2) && Math.max(y1, y2) >= Math.min(x1, x2);
}

View file

@ -2271,13 +2271,13 @@ public class LocaleController {
int dateYear = rightNow.get(Calendar.YEAR);
if (dateDay == day && year == dateYear && useToday) {
return LocaleController.formatString("TodayAtFormattedWithToday", R.string.TodayAtFormattedWithToday, getInstance().getFormatterDay().format(new Date(date)));
return LocaleController.formatString(R.string.TodayAtFormattedWithToday, getInstance().getFormatterDay().format(new Date(date)));
} else if (dateDay + 1 == day && year == dateYear && useToday) {
return LocaleController.formatString("YesterdayAtFormatted", R.string.YesterdayAtFormatted, getInstance().getFormatterDay().format(new Date(date)));
return LocaleController.formatString(R.string.YesterdayAtFormatted, getInstance().getFormatterDay().format(new Date(date)));
} else if (Math.abs(System.currentTimeMillis() - date) < 31536000000L) {
return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().getChatDate().format(new Date(date)), getInstance().getFormatterDay().format(new Date(date)));
return LocaleController.formatString(R.string.formatDateAtTime, getInstance().getChatDate().format(new Date(date)), getInstance().getFormatterDay().format(new Date(date)));
} else {
return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().getChatFullDate().format(new Date(date)), getInstance().getFormatterDay().format(new Date(date)));
return LocaleController.formatString(R.string.formatDateAtTime, getInstance().getChatFullDate().format(new Date(date)), getInstance().getFormatterDay().format(new Date(date)));
}
} catch (Exception e) {
FileLog.e(e);

View file

@ -48,6 +48,9 @@ import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.MediaStore;
@ -5602,24 +5605,30 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
private static class VideoConvertRunnable implements Runnable {
private VideoConvertMessage convertMessage;
private final VideoConvertMessage convertMessage;
private final Handler handler;
private VideoConvertRunnable(VideoConvertMessage message) {
convertMessage = message;
private VideoConvertRunnable(VideoConvertMessage message, Handler handler) {
this.convertMessage = message;
this.handler = handler;
}
@Override
public void run() {
MediaController.getInstance().convertVideo(convertMessage);
MediaController.getInstance().convertVideo(convertMessage, handler);
}
public static void runConversion(final VideoConvertMessage obj) {
HandlerThread handlerThread = new HandlerThread("VideoConvertRunnableThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
new Thread(() -> {
try {
VideoConvertRunnable wrapper = new VideoConvertRunnable(obj);
VideoConvertRunnable wrapper = new VideoConvertRunnable(obj, handler);
Thread th = new Thread(wrapper, "VideoConvertRunnable");
th.start();
th.join();
handlerThread.join();
} catch (Exception e) {
FileLog.e(e);
}
@ -5628,7 +5637,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
}
private boolean convertVideo(final VideoConvertMessage convertMessage) {
private boolean convertVideo(final VideoConvertMessage convertMessage, final Handler handler) {
MessageObject messageObject = convertMessage.messageObject;
VideoEditedInfo info = convertMessage.videoEditedInfo;
if (messageObject == null || info == null) {
@ -5734,7 +5743,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
callback,
info);
convertVideoParams.soundInfos.addAll(info.mixedSoundInfos);
boolean error = videoConvertor.convertVideo(convertVideoParams);
boolean error = videoConvertor.convertVideo(convertVideoParams, handler);
boolean canceled = info.canceled;

View file

@ -6220,7 +6220,9 @@ public class MediaDataController extends BaseController {
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) {
messageObject.generateGameMessageText(null);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {
messageObject.generatePaymentSentMessageText(null);
messageObject.generatePaymentSentMessageText(null, false);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSentMe) {
messageObject.generatePaymentSentMessageText(null, true);
}
break;
}
@ -6690,7 +6692,9 @@ public class MediaDataController extends BaseController {
} else if (m.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) {
m.generateGameMessageText(null);
} else if (m.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {
m.generatePaymentSentMessageText(null);
m.generatePaymentSentMessageText(null, false);
} else if (m.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSentMe) {
m.generatePaymentSentMessageText(null, true);
}
}
changed = true;
@ -9648,4 +9652,92 @@ public class MediaDataController extends BaseController {
}
}
}
public static class SearchStickersKey {
public final boolean emojis;
public final String lang_code;
public final String q;
public SearchStickersKey(boolean emojis, String lang_code, String q) {
this.emojis = emojis;
this.lang_code = lang_code;
this.q = q;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SearchStickersKey that = (SearchStickersKey) o;
return emojis == that.emojis && Objects.equals(lang_code, that.lang_code) && Objects.equals(q, that.q);
}
@Override
public int hashCode() {
return Objects.hash(emojis, lang_code, q);
}
}
private static class SearchStickersResult {
public final ArrayList<TLRPC.Document> documents = new ArrayList<>();
public Integer next_offset;
public void apply(TLRPC.TL_messages_foundStickers r) {
documents.addAll(r.stickers);
next_offset = (r.flags & 1) != 0 ? r.next_offset : null;
}
}
private final HashMap<SearchStickersKey, Integer> loadingSearchStickersKeys = new HashMap<>();
private final android.util.LruCache<SearchStickersKey, SearchStickersResult> searchStickerResults = new android.util.LruCache<>(25);
public SearchStickersKey searchStickers(boolean emojis, String lang_code, String q, Utilities.Callback<ArrayList<TLRPC.Document>> whenDone) {
return searchStickers(emojis, lang_code, q, whenDone, false);
}
public SearchStickersKey searchStickers(boolean emojis, String lang_code, String q, Utilities.Callback<ArrayList<TLRPC.Document>> whenDone, boolean next) {
if (whenDone == null) return null;
final SearchStickersKey key = new SearchStickersKey(emojis, lang_code, q);
SearchStickersResult cached = searchStickerResults.get(key);
if ((cached == null || cached.next_offset != null && next) && !loadingSearchStickersKeys.containsKey(key)) {
loadingSearchStickersKeys.put(key, 0);
MediaDataController.getInstance(currentAccount).getEmojiSuggestions(new String[]{lang_code}, q, true, (result, a) -> {
if (!loadingSearchStickersKeys.containsKey(key)) return;
StringBuilder s = new StringBuilder();
for (KeywordResult r : result) {
if (!TextUtils.isEmpty(r.emoji) && !r.emoji.startsWith("animated_")) {
s.append(r.emoji);
}
}
TLRPC.TL_messages_searchStickers req = new TLRPC.TL_messages_searchStickers();
req.emojis = key.emojis;
if (!TextUtils.isEmpty(key.lang_code)) {
req.lang_code.add(key.lang_code);
}
req.emoticon = s.toString();
req.q = key.q;
req.limit = 50;
req.offset = cached == null ? 0 : cached.next_offset;
final int reqId = getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> {
loadingSearchStickersKeys.remove(key);
SearchStickersResult finalResult = cached != null ? cached : new SearchStickersResult();
if (res instanceof TLRPC.TL_messages_foundStickers) {
finalResult.apply((TLRPC.TL_messages_foundStickers) res);
}
searchStickerResults.put(key, finalResult);
whenDone.run(finalResult.documents);
}));
loadingSearchStickersKeys.put(key, reqId);
}, false);
} else if (cached != null) {
whenDone.run(cached.documents);
} else {
whenDone.run(new ArrayList<>());
}
return key;
}
public void cancelSearchStickers(SearchStickersKey key) {
if (key == null) return;
final Integer reqId = loadingSearchStickersKeys.remove(key);
if (reqId != null && reqId != 0) {
getConnectionsManager().cancelRequest(reqId, true);
}
}
}

View file

@ -3533,16 +3533,11 @@ public class MessageObject {
return !(replyMessageObject == null || replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionHistoryClear || replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate);
}
public void generatePaymentSentMessageText(TLRPC.User fromUser) {
public void generatePaymentSentMessageText(TLRPC.User fromUser, boolean me) {
if (fromUser == null) {
fromUser = MessagesController.getInstance(currentAccount).getUser(getDialogId());
}
String name;
if (fromUser != null) {
name = UserObject.getFirstName(fromUser);
} else {
name = "";
}
final String name = fromUser != null ? UserObject.getFirstName(fromUser) : "";
String currency;
try {
if (StarsController.currency.equals(messageOwner.action.currency)) {
@ -3555,16 +3550,28 @@ public class MessageObject {
FileLog.e(e);
}
if (replyMessageObject != null && getMedia(replyMessageObject) instanceof TLRPC.TL_messageMediaInvoice) {
if (messageOwner.action.recurring_init) {
if (messageOwner.action.subscription_until_date != 0) {
if (me) {
messageText = formatString(R.string.PaymentSuccessfullyPaidMeSubscription, name, currency, getMedia(replyMessageObject).title, LocaleController.formatDateTime(messageOwner.action.subscription_until_date, false));
} else {
messageText = formatString(R.string.PaymentSuccessfullyPaidSubscription, currency, name, getMedia(replyMessageObject).title, LocaleController.formatDateTime(messageOwner.action.subscription_until_date, false));
}
} else if (messageOwner.action.recurring_init && !me) {
messageText = formatString(R.string.PaymentSuccessfullyPaidRecurrent, currency, name, getMedia(replyMessageObject).title);
} else {
messageText = formatString("PaymentSuccessfullyPaid", R.string.PaymentSuccessfullyPaid, currency, name, getMedia(replyMessageObject).title);
messageText = formatString(R.string.PaymentSuccessfullyPaid, currency, name, getMedia(replyMessageObject).title);
}
} else {
if (messageOwner.action.recurring_init) {
if (messageOwner.action.subscription_until_date != 0) {
if (me) {
messageText = formatString(R.string.PaymentSuccessfullyPaidMeNoItemSubscription, name, currency, LocaleController.formatDateTime(messageOwner.action.subscription_until_date, false));
} else {
messageText = formatString(R.string.PaymentSuccessfullyPaidSubscriptionNoItem, currency, name, LocaleController.formatDateTime(messageOwner.action.subscription_until_date, false));
}
} else if (messageOwner.action.recurring_init && !me) {
messageText = formatString(R.string.PaymentSuccessfullyPaidNoItemRecurrent, currency, name);
} else {
messageText = formatString("PaymentSuccessfullyPaidNoItem", R.string.PaymentSuccessfullyPaidNoItem, currency, name);
messageText = formatString(R.string.PaymentSuccessfullyPaidNoItem, currency, name);
}
}
messageText = StarsIntroActivity.replaceStars(messageText);
@ -4414,17 +4421,31 @@ public class MessageObject {
messageText = replaceWithLink(AndroidUtilities.replaceTags(LocaleController.formatPluralStringComma("ActionStarGiveawayPrize", (int) action.stars)), "un1", chat);
} else if (messageOwner.action instanceof TLRPC.TL_messageActionStarGift) {
TLRPC.TL_messageActionStarGift action = (TLRPC.TL_messageActionStarGift) messageOwner.action;
int stars = 0;
if (action.gift != null) {
stars = (int) action.gift.stars;
}
if (fromObject instanceof TLRPC.User && ((TLRPC.User) fromObject).self && !action.forceIn) {
TLRPC.User user = getUser(users, sUsers, messageOwner.peer_id.user_id);
messageText = replaceWithLink(AndroidUtilities.replaceTags(getString(R.string.ActionGiftOutbound)), "un1", user);
if (action.message != null && !TextUtils.isEmpty(action.message.text)) {
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(action.message.text);
addEntitiesToText(stringBuilder, action.message.entities, isOutOwner(), false, false, false);
messageTextShort = stringBuilder;
} else {
messageTextShort = getString(R.string.ActionStarGift);
}
} else if (fromObject instanceof TLRPC.User && UserObject.isService(((TLRPC.User) fromObject).id)) {
messageText = TextUtils.replace(AndroidUtilities.replaceTags(getString(R.string.ActionGiftInbound)), new String[] {"un1"}, new CharSequence[]{ getString(R.string.StarsTransactionUnknown) });
} else {
messageText = replaceWithLink(AndroidUtilities.replaceTags(getString(R.string.ActionGiftInbound)), "un1", fromObject);
}
int stars = 0;
if (action.gift != null) {
stars = (int) action.gift.stars;
if (action.message != null && !TextUtils.isEmpty(action.message.text)) {
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(action.message.text);
addEntitiesToText(stringBuilder, action.message.entities, isOutOwner(), false, false, false);
messageTextShort = stringBuilder;
} else {
messageTextShort = getString(R.string.ActionStarGift);
}
}
int i = messageText.toString().indexOf("un2");
if (i != -1) {
@ -4840,8 +4861,11 @@ public class MessageObject {
}
}
} else if (messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {
TLRPC.User user = getUser(users, sUsers, getDialogId());
generatePaymentSentMessageText(user);
final TLRPC.User user = getUser(users, sUsers, getDialogId());
generatePaymentSentMessageText(user, false);
} else if (messageOwner.action instanceof TLRPC.TL_messageActionPaymentSentMe) {
final TLRPC.User user = getUser(users, sUsers, getDialogId());
generatePaymentSentMessageText(user, true);
} else if (messageOwner.action instanceof TLRPC.TL_messageActionBotAllowed) {
String domain = ((TLRPC.TL_messageActionBotAllowed) messageOwner.action).domain;
TLRPC.BotApp botApp = ((TLRPC.TL_messageActionBotAllowed) messageOwner.action).app;

View file

@ -639,6 +639,11 @@ public class MessagesController extends BaseController implements NotificationCe
public float starsUsdSellRate1000;
public float starsUsdWithdrawRate1000;
public boolean sponsoredLinksInappAllow;
public Set<String> starrefStartParamPrefixes = new HashSet<>();
public boolean starrefProgramAllowed;
public boolean starrefConnectAllowed;
public int starrefMinCommissionPermille;
public int starrefMaxCommissionPermille;
public long paidReactionsAnonymousTime;
public Boolean paidReactionsAnonymous;
@ -1605,6 +1610,11 @@ public class MessagesController extends BaseController implements NotificationCe
starsUsdSellRate1000 = mainPreferences.getFloat("starsUsdSellRate1000", 2000);
starsUsdWithdrawRate1000 = mainPreferences.getFloat("starsUsdWithdrawRate1000", 1200);
sponsoredLinksInappAllow = mainPreferences.getBoolean("sponsoredLinksInappAllow", false);
starrefProgramAllowed = mainPreferences.getBoolean("starrefProgramAllowed", false);
starrefConnectAllowed = mainPreferences.getBoolean("starrefConnectAllowed", false);
starrefStartParamPrefixes = mainPreferences.getStringSet("starrefStartParamPrefixes", new HashSet<>(Arrays.asList("_tgr_")));
starrefMinCommissionPermille = mainPreferences.getInt("starrefMinCommissionPermille", 1);
starrefMaxCommissionPermille = mainPreferences.getInt("starrefMaxCommissionPermille", 400);
paidReactionsAnonymousTime = mainPreferences.getLong("paidReactionsAnonymousTime", 0);
paidReactionsAnonymous = mainPreferences.contains("paidReactionsAnonymous") && (System.currentTimeMillis() - paidReactionsAnonymousTime) < 1000 * 60 * 60 * 2 ? mainPreferences.getBoolean("paidReactionsAnonymous", false) : null;
scheduleTranscriptionUpdate();
@ -4288,6 +4298,25 @@ public class MessagesController extends BaseController implements NotificationCe
}
break;
}
case "starref_start_param_prefixes": {
HashSet<String> newPrefixes = new HashSet<>();
if (value.value instanceof TLRPC.TL_jsonArray) {
TLRPC.TL_jsonArray array = (TLRPC.TL_jsonArray) value.value;
for (int b = 0, N2 = array.value.size(); b < N2; b++) {
TLRPC.JSONValue val = array.value.get(b);
if (val instanceof TLRPC.TL_jsonString) {
TLRPC.TL_jsonString string = (TLRPC.TL_jsonString) val;
newPrefixes.add(string.value.toLowerCase());
}
}
}
if (!starrefStartParamPrefixes.equals(newPrefixes)) {
starrefStartParamPrefixes = newPrefixes;
editor.putStringSet("starrefStartParamPrefixes", starrefStartParamPrefixes);
changed = true;
}
break;
}
case "weather_search_username": {
if (value.value instanceof TLRPC.TL_jsonString) {
TLRPC.TL_jsonString str = (TLRPC.TL_jsonString) value.value;
@ -4406,6 +4435,50 @@ public class MessagesController extends BaseController implements NotificationCe
}
break;
}
case "starref_program_allowed": {
if (value.value instanceof TLRPC.TL_jsonBool) {
TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value;
if (bool.value != starrefProgramAllowed) {
starrefProgramAllowed = bool.value;
editor.putBoolean("starrefProgramAllowed", starrefProgramAllowed);
changed = true;
}
}
break;
}
case "starref_connect_allowed": {
if (value.value instanceof TLRPC.TL_jsonBool) {
TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value;
if (bool.value != starrefConnectAllowed) {
starrefConnectAllowed = bool.value;
editor.putBoolean("starrefConnectAllowed", starrefConnectAllowed);
changed = true;
}
}
break;
}
case "starref_min_commission_permille": {
if (value.value instanceof TLRPC.TL_jsonNumber) {
TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value;
if (num.value != starrefMinCommissionPermille) {
starrefMinCommissionPermille = (int) num.value;
editor.putInt("starrefMinCommissionPermille", starrefMinCommissionPermille);
changed = true;
}
}
break;
}
case "starref_max_commission_permille": {
if (value.value instanceof TLRPC.TL_jsonNumber) {
TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value;
if (num.value != starrefMaxCommissionPermille) {
starrefMaxCommissionPermille = (int) num.value;
editor.putInt("starrefMaxCommissionPermille", starrefMaxCommissionPermille);
changed = true;
}
}
break;
}
}
}
@ -10765,7 +10838,9 @@ public class MessagesController extends BaseController implements NotificationCe
} else if (msg.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) {
msg.generateGameMessageText(null);
} else if (msg.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {
msg.generatePaymentSentMessageText(null);
msg.generatePaymentSentMessageText(null, false);
} else if (msg.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSentMe) {
msg.generatePaymentSentMessageText(null, true);
}
break;
}
@ -22128,4 +22203,12 @@ public class MessagesController extends BaseController implements NotificationCe
return paidReactionsAnonymous;
}
public boolean shouldShowMoveCaptionHint() {
return getMainSettings().getInt("movecaptionhint", 0) < 24 || BuildVars.DEBUG_PRIVATE_VERSION;
}
public void incrementMoveCaptionHint() {
getMainSettings().edit().putInt("movecaptionhint", getMainSettings().getInt("movecaptionhint", 0) + 1).apply();
}
}

View file

@ -263,6 +263,8 @@ public class NotificationCenter {
public static final int starGiftSoldOut = totalEvents++;
public static final int updateStories = totalEvents++;
public static final int botDownloadsUpdate = totalEvents++;
public static final int channelSuggestedBotsUpdate = totalEvents++;
public static final int channelConnectedBotsUpdate = totalEvents++;
//global
public static final int pushMessagesUpdated = totalEvents++;

View file

@ -1802,7 +1802,7 @@ public class NotificationsController extends BaseController {
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
String date = LocaleController.formatString(R.string.formatDateAtTime, LocaleController.getInstance().getFormatterYear().format(((long) messageObject.messageOwner.date) * 1000), LocaleController.getInstance().getFormatterDay().format(((long) messageObject.messageOwner.date) * 1000));
return LocaleController.formatString(R.string.NotificationUnrecognizedDevice, getUserConfig().getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSentMe) {
return messageObject.messageText.toString();
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionStarGift || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium) {
return messageObject.messageText.toString();
@ -2431,7 +2431,7 @@ public class NotificationsController extends BaseController {
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) {
String date = LocaleController.formatString(R.string.formatDateAtTime, LocaleController.getInstance().getFormatterYear().format(((long) messageObject.messageOwner.date) * 1000), LocaleController.getInstance().getFormatterDay().format(((long) messageObject.messageOwner.date) * 1000));
msg = LocaleController.formatString(R.string.NotificationUnrecognizedDevice, getUserConfig().getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address);
} else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) {