update to 12.10.1 (7038)

This commit is contained in:
Arseny271 2026-08-25 15:02:54 +04:00
parent 4f25852f9e
commit 62b56a07ca
46 changed files with 1119 additions and 609 deletions

View file

@ -1,43 +1,50 @@
FROM gradle:8.7.0-jdk17
FROM gradle:8.11.1-jdk17
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/commandlinetools-linux-7302050_latest.zip
ENV ANDROID_API_LEVEL android-35
ENV ANDROID_BUILD_TOOLS_VERSION 35.0.0
ENV ANDROID_HOME /usr/local/android-sdk-linux
ENV ANDROID_NDK_VERSION 21.4.7075529
ENV ANDROID_VERSION 35
ENV ANDROID_NDK_HOME ${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/
ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
ENV ANDROID_CMDLINE_TOOLS_VERSION=15859902
ENV ANDROID_SDK_URL=https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS_VERSION}_latest.zip
RUN mkdir "$ANDROID_HOME" .android && \
cd "$ANDROID_HOME" && \
curl -o sdk.zip $ANDROID_SDK_URL && \
unzip sdk.zip && \
rm sdk.zip
ENV ANDROID_HOME=/usr/local/android-sdk-linux
RUN yes | ${ANDROID_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_HOME --licenses
RUN $ANDROID_HOME/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_HOME --update
RUN $ANDROID_HOME/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_HOME "build-tools;30.0.3" \
ENV ANDROID_API_LEVEL=android-36
ENV ANDROID_VERSION=36
ENV ANDROID_BUILD_TOOLS_VERSION=36.0.0
ENV ANDROID_NDK_VERSION=27.2.12479018
ENV ANDROID_NDK_HOME=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}
ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
ENV PATH=${PATH}:${ANDROID_NDK_HOME}
ENV PATH=${PATH}:${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin
RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" /home/gradle/.android && \
cd /tmp && \
curl -fL "${ANDROID_SDK_URL}" -o commandlinetools.zip && \
unzip commandlinetools.zip && \
mv cmdline-tools "${ANDROID_HOME}/cmdline-tools/latest" && \
rm commandlinetools.zip
RUN yes | sdkmanager --sdk_root="${ANDROID_HOME}" --licenses
RUN sdkmanager \
--sdk_root="${ANDROID_HOME}" \
"build-tools;36.0.0" \
"build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools" \
"ndk;$ANDROID_NDK_VERSION"
RUN cp $ANDROID_HOME/build-tools/30.0.3/dx $ANDROID_HOME/build-tools/35.0.0/dx
RUN cp $ANDROID_HOME/build-tools/30.0.3/lib/dx.jar $ANDROID_HOME/build-tools/35.0.0/lib/dx.jar
ENV PATH ${ANDROID_NDK_HOME}:$PATH
ENV PATH ${ANDROID_NDK_HOME}/prebuilt/linux-x86_64/bin/:$PATH
"ndk;${ANDROID_NDK_VERSION}" \
"cmake;3.22.1"
CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && \
mkdir -p /home/gradle/TMessagesProj/build/outputs/bundle && \
mkdir -p /home/source/TMessagesProj/build/outputs/native-debug-symbols && \
cp -R /home/source/. /home/gradle && \
cd /home/gradle && \
gradle :TMessagesProj_App:bundleBundleAfat_SDK23Release && \
gradle :TMessagesProj_App:bundleBundleAfatRelease && \
gradle :TMessagesProj_AppStandalone:assembleAfatStandalone && \
gradle :TMessagesProj_App:assembleAfatRelease && \
gradle :TMessagesProj_AppHuawei:assembleAfatRelease && \
gradle --parallel \
:TMessagesProj_App:bundleBundleAfat_SDK23Release \
:TMessagesProj_App:bundleBundleAfatRelease \
:TMessagesProj_AppStandalone:assembleAfatStandalone \
:TMessagesProj_App:assembleAfatRelease \
:TMessagesProj_AppHuawei:assembleAfatRelease --stacktrace && \
cp -R /home/gradle/TMessagesProj_App/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && \
cp -R /home/gradle/TMessagesProj_AppHuawei/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && \
cp -R /home/gradle/TMessagesProj_AppStandalone/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && \
cp -R /home/gradle/TMessagesProj_App/build/outputs/bundle/. /home/source/TMessagesProj/build/outputs/bundle
cp -R /home/gradle/TMessagesProj_App/build/outputs/bundle/. /home/source/TMessagesProj/build/outputs/bundle

View file

@ -24,7 +24,7 @@ MTproto protocol manuals: https://core.telegram.org/mtproto
**Note**: In order to support [reproducible builds](https://core.telegram.org/reproducible-builds), this repo contains dummy release.keystore, google-services.json and filled variables inside BuildVars.java. Before publishing your own APKs please make sure to replace all these files with your own.
You will require Android Studio 2025.1.4, Android NDK 27.2.12479018 and Android SDK 35.
You will require Android Studio 2025.1.4, Android NDK 27.2.12479018 and Android SDK 36.
1. Clone the Telegram source code with its submodules:
```bash

View file

@ -61,7 +61,7 @@ dependencies {
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
implementation 'com.stripe:stripe-android:2.0.2'
implementation 'com.google.mlkit:language-id:17.0.6'
implementation 'com.android.billingclient:billing:7.1.1'
implementation 'com.android.billingclient:billing:8.0.0'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.google.guava:guava:31.1-android'
implementation 'com.google.android.play:integrity:1.3.0'
@ -99,8 +99,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
ndkVersion "27.2.12479018"
sourceSets.main.jniLibs.srcDirs = ['./jni/']
@ -127,7 +127,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
targetSdkVersion 36
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']
@ -135,8 +135,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' //, '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}
}

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10.2)
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_FLAGS "-std=c++14 -DANDROID -g")
set(CMAKE_C_FLAGS "-w -std=c11 -DANDROID -D_LARGEFILE_SOURCE=1 -g -Wno-error=implicit-function-declaration")
@ -13,6 +13,12 @@ else()
enable_language(ASM_NASM)
endif()
set(CAN_COMPILE_SME FALSE CACHE INTERNAL "Disable libyuv SME" FORCE)
add_subdirectory(
third_party/libyuv
${CMAKE_CURRENT_BINARY_DIR}/libyuv
EXCLUDE_FROM_ALL)
add_library(avutil STATIC IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/ffmpeg/${ANDROID_ABI}/libavutil.a)
@ -84,7 +90,7 @@ target_link_libraries(tgnet
# tlottie (prebuilt Rust static library)
add_library(tlottie STATIC IMPORTED)
set_target_properties(tlottie PROPERTIES
IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/tlottie_lib/${ANDROID_ABI}/libtlottie.a)
IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/prebuild/${ANDROID_ABI}/libtlottie.a)
#sqlite
add_library(sqlite STATIC
@ -157,32 +163,6 @@ target_compile_options(${NATIVE_LIB} PUBLIC
target_compile_definitions(${NATIVE_LIB} PUBLIC
BSD=1 NULL=0 SOCKLEN_T=socklen_t ANDROID_NDK DISABLE_IMPORTGL AVOID_TABLES ANDROID_TILE_BASED_DECODE __STDC_CONSTANT_MACROS ANDROID_ARMV6_IDCT OPUS_BUILD FIXED_POINT USE_ALLOCA restrict= __EMX__ LOCALE_NOT_USED HAVE_LRINT HAVE_LRINTF)
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
set_target_properties(${NATIVE_LIB} PROPERTIES
ANDROID_ARM_NEON FALSE
ANDROID_ARM_MODE arm)
target_compile_definitions(${NATIVE_LIB} PUBLIC
ANDROID_ARM_NEON=false)
target_sources(${NATIVE_LIB} PRIVATE
third_party/libyuv/source/compare_neon.cc
third_party/libyuv/source/rotate_neon.cc
third_party/libyuv/source/row_neon.cc
third_party/libyuv/source/scale_neon.cc)
else()
set_target_properties(${NATIVE_LIB} PROPERTIES
ANDROID_ARM_NEON FALSE
ANDROID_ARM_MODE arm)
endif()
if (${ANDROID_ABI} STREQUAL "armeabi-v7a" OR ${ANDROID_ABI} STREQUAL "arm64-v8a")
target_compile_definitions(${NATIVE_LIB} PUBLIC
LIBYUV_NEON)
elseif(${ANDROID_ABI} STREQUAL "x86")
target_compile_definitions(${NATIVE_LIB} PUBLIC
x86fix)
endif()
target_sources(${NATIVE_LIB} PRIVATE
third_party/xiph/opusfile/src/info.c
@ -190,49 +170,7 @@ target_sources(${NATIVE_LIB} PRIVATE
third_party/xiph/opusfile/src/opusfile.c
third_party/xiph/opusfile/src/stream.c
third_party/xiph/ogg/src/bitwise.c
third_party/xiph/ogg/src/framing.c
third_party/libyuv/source/compare_common.cc
third_party/libyuv/source/compare_gcc.cc
third_party/libyuv/source/compare_neon64.cc
third_party/libyuv/source/compare_win.cc
third_party/libyuv/source/compare.cc
third_party/libyuv/source/convert_argb.cc
third_party/libyuv/source/convert_from_argb.cc
third_party/libyuv/source/convert_from.cc
third_party/libyuv/source/convert_jpeg.cc
third_party/libyuv/source/convert_to_argb.cc
third_party/libyuv/source/convert_to_i420.cc
third_party/libyuv/source/convert.cc
third_party/libyuv/source/cpu_id.cc
third_party/libyuv/source/mjpeg_decoder.cc
third_party/libyuv/source/mjpeg_validate.cc
third_party/libyuv/source/planar_functions.cc
third_party/libyuv/source/rotate_any.cc
third_party/libyuv/source/rotate_argb.cc
third_party/libyuv/source/rotate_common.cc
third_party/libyuv/source/rotate_gcc.cc
third_party/libyuv/source/rotate_neon64.cc
third_party/libyuv/source/rotate_win.cc
third_party/libyuv/source/rotate.cc
third_party/libyuv/source/row_any.cc
third_party/libyuv/source/row_common.cc
third_party/libyuv/source/row_gcc.cc
third_party/libyuv/source/row_neon64.cc
third_party/libyuv/source/row_win.cc
third_party/libyuv/source/scale_any.cc
third_party/libyuv/source/scale_argb.cc
third_party/libyuv/source/scale_common.cc
third_party/libyuv/source/scale_gcc.cc
third_party/libyuv/source/scale_neon64.cc
third_party/libyuv/source/scale_win.cc
third_party/libyuv/source/scale.cc
third_party/libyuv/source/video_common.cc
third_party/libyuv/source/scale_uv.cc
third_party/libyuv/source/rotate_lsx.cc
third_party/libyuv/source/row_lasx.cc
third_party/libyuv/source/row_lsx.cc
third_party/libyuv/source/scale_lsx.cc
third_party/libyuv/source/scale_rgb.cc)
third_party/xiph/ogg/src/framing.c)
target_include_directories(${NATIVE_LIB} PUBLIC
third_party/xiph/opus/include
@ -274,6 +212,7 @@ target_link_libraries(${NATIVE_LIB}
libopus
tde2e
tdutils
yuv
avutil
ssl
crypto

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,66 @@
#!/bin/sh
#
# Top-level orchestrator for the tlottie Android build.
#
# Responsibilities kept here (outside the container):
# 1. remove stale libtlottie.a files, so a failed build can never leave a
# previous artifact looking up to date
# 2. build the tlottie Docker image
# 3. run it with the right mounts and platform pin
#
# Everything about *how* tlottie itself is compiled (rustc flags, profile,
# features, per-ABI loop) lives in scripts/tlottie/entrypoint.sh, which runs
# inside the container - see that file to change build settings.
#
# No environment variables are read - paths and settings are hardcoded
# below. Layout this script expects (relative to this file):
# arm64-v8a/, armeabi-v7a/, x86/, x86_64/ - output directories
# scripts/tlottie/Dockerfile - build environment for tlottie
# ../tlottie - tlottie source (sibling of
# this repo checkout)
set -eu
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
tlottie_dir=$(CDPATH= cd -- "$script_dir/../tlottie" && pwd)
dockerfile_dir="$script_dir/scripts/tlottie"
image_tag=tlottie-build
platform=linux/amd64
if [ ! -f "$tlottie_dir/Cargo.toml" ]; then
echo "error: tlottie Cargo.toml not found at $tlottie_dir/Cargo.toml" >&2
exit 1
fi
echo "Removing previous tlottie archives"
for abi in arm64-v8a armeabi-v7a x86 x86_64; do
dest="$script_dir/$abi/libtlottie.a"
if [ -f "$dest" ]; then
rm -f "$dest"
echo " removed $dest"
fi
if [ ! -d "$script_dir/$abi" ]; then
echo "error: output directory does not exist: $script_dir/$abi" >&2
exit 1
fi
done
echo "Building tlottie build image ($platform)"
# Plain "docker build" already uses BuildKit (and loads the result into the
# local image store) on any reasonably current Docker install. Swap for
# "docker buildx build --load ..." if your setup needs an explicit builder.
docker build \
--platform "$platform" \
-t "$image_tag" \
"$dockerfile_dir"
echo "Running tlottie build in container"
docker run --rm \
--platform "$platform" \
-v "$script_dir:/work" \
-v "$tlottie_dir:/tlottie:ro" \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
"$image_tag"
echo "All tlottie Android archives are ready."

View file

@ -0,0 +1,123 @@
#!/usr/bin/env bash
# Compile static OpenH264 libraries for Android.
#
# The resulting archives are placed in ABI directories next to this script:
#
# arm64-v8a/libopenh264.a
# armeabi-v7a/libopenh264.a
# x86_64/libopenh264.a
# x86/libopenh264.a
#
# build_openh264/ is used as temporary workspace. It is removed after all
# architectures are built successfully and preserved if the build fails.
#
# OpenH264 is built with its upstream Makefile, which selects the appropriate
# sources and architecture-specific optimizations (including NEON/assembly).
#
# Optional environment overrides:
# OPENH264_SOURCE_DIR=/path/to/openh264
# ANDROID_NDK_HOME=/path/to/ndk
# NDK_VERSION=27.2.12479018
# API=21
# ABIS="arm64-v8a armeabi-v7a x86_64 x86"
# JOBS=16
set -Eeuo pipefail
NDK_VERSION="${NDK_VERSION:-27.2.12479018}"
API="${API:-21}"
ABIS="${ABIS:-arm64-v8a armeabi-v7a x86_64 x86}"
JOBS="${JOBS:-$(nproc)}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OPENH264_SRC="${OPENH264_SOURCE_DIR:-$SCRIPT_DIR/../third_party/openh264}"
BUILD_DIR="$SCRIPT_DIR/build_openh264"
: "${ANDROID_NDK_HOME:=${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}/ndk/$NDK_VERSION}"
[ -d "$ANDROID_NDK_HOME" ] || {
echo "ERROR: Android NDK not found: $ANDROID_NDK_HOME" >&2
exit 1
}
[ -f "$OPENH264_SRC/Makefile" ] || {
echo "ERROR: OpenH264 Makefile not found: $OPENH264_SRC/Makefile" >&2
echo " Set OPENH264_SOURCE_DIR if the source tree is elsewhere." >&2
exit 1
}
command -v make >/dev/null || {
echo "ERROR: make is required" >&2
exit 1
}
if [[ " $ABIS " == *" x86 "* || " $ABIS " == *" x86_64 "* ]]; then
command -v nasm >/dev/null || {
echo "ERROR: nasm is required for OpenH264 x86/x86_64 builds" >&2
exit 1
}
fi
abi_to_arch() {
case "$1" in
armeabi-v7a) echo arm ;;
arm64-v8a) echo arm64 ;;
x86) echo x86 ;;
x86_64) echo x86_64 ;;
*)
echo "ERROR: unsupported ABI: $1" >&2
return 1
;;
esac
}
copy_source_tree() {
local dst="$1"
rm -rf "$dst"
mkdir -p "$dst"
cp -a --reflink=auto "$OPENH264_SRC/." "$dst/"
}
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
for abi in $ABIS; do
arch="$(abi_to_arch "$abi")"
work_src="$BUILD_DIR/$abi"
echo
echo "==> Building OpenH264 for $abi (ARCH=$arch, API=$API)"
copy_source_tree "$work_src"
make -C "$work_src" \
-j"$JOBS" \
V=No \
OS=android \
ARCH="$arch" \
NDKROOT="$ANDROID_NDK_HOME" \
TARGET="android-$API" \
NDKLEVEL="$API" \
BUILDTYPE=Release \
ENABLEPIC=Yes \
libopenh264.a
[ -f "$work_src/libopenh264.a" ] || {
echo "ERROR: build succeeded but libopenh264.a was not produced for $abi" >&2
exit 1
}
install -D -m 644 \
"$work_src/libopenh264.a" \
"$SCRIPT_DIR/$abi/libopenh264.a"
echo "==> $SCRIPT_DIR/$abi/libopenh264.a"
done
rm -rf "$BUILD_DIR"
echo
echo "OpenH264 static build completed."
for abi in $ABIS; do
echo " $SCRIPT_DIR/$abi/libopenh264.a"
done

View file

@ -0,0 +1,38 @@
ARG RUST_VERSION=1.98.0
FROM --platform=linux/amd64 debian:bookworm-slim
ARG RUST_VERSION
ENV DEBIAN_FRONTEND=noninteractive \
RUSTUP_HOME=/opt/rustup \
CARGO_HOME=/opt/cargo \
PATH=/opt/cargo/bin:/opt/rustup/bin:$PATH \
TZ=UTC \
LC_ALL=C \
SOURCE_DATE_EPOCH=1 \
CARGO_INCREMENTAL=0
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
sh -s -- -y \
--profile minimal \
--default-toolchain "$RUST_VERSION" \
--no-modify-path \
&& chmod -R a+rX /opt/rustup /opt/cargo
RUN rustup target add \
aarch64-linux-android \
armv7-linux-androideabi \
i686-linux-android \
x86_64-linux-android
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
WORKDIR /work
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View file

@ -0,0 +1,103 @@
#!/bin/sh
#
# Runs inside the tlottie build container. /work is the host repo root
# (bind-mounted read-write, so output ABI directories live at
# /work/<abi>/), /tlottie is the tlottie source (bind-mounted read-only).
# The toolchain itself (rustc, cargo, Android targets, build-essential)
# is already baked into the image at `docker build` time - see Dockerfile.
set -eu
tlottie_dir=/tlottie
manifest="$tlottie_dir/Cargo.toml"
profile=release-nostd
features=cpu,no-std,c-api
out_root=/work
if [ ! -f "$manifest" ]; then
echo "error: tlottie Cargo.toml not found at $manifest" >&2
exit 1
fi
# Keep cargo's target dir inside the container, not on the bind-mounted
# host repo - it's build-only scratch space and would otherwise leave a
# large, host-owned cache sitting in the checkout.
target_dir=/build/target
mkdir -p "$target_dir"
export CARGO_TARGET_DIR="$target_dir"
rust_sysroot=$(rustc --print sysroot)
# Do not inherit per-machine compiler flags. CARGO_ENCODED_RUSTFLAGS takes
# precedence over RUSTFLAGS and safely supports spaces in paths.
unset RUSTFLAGS
CARGO_ENCODED_RUSTFLAGS=
append_rustflag() {
if [ -n "$CARGO_ENCODED_RUSTFLAGS" ]; then
CARGO_ENCODED_RUSTFLAGS="$CARGO_ENCODED_RUSTFLAGS$(printf '\037')"
fi
CARGO_ENCODED_RUSTFLAGS="$CARGO_ENCODED_RUSTFLAGS$1"
}
append_rustflag "--remap-path-prefix=$tlottie_dir=/tlottie"
append_rustflag "--remap-path-prefix=$target_dir=/tlottie-target"
append_rustflag "--remap-path-prefix=$rust_sysroot=/rust-sysroot"
append_rustflag "--remap-path-prefix=$CARGO_HOME=/cargo-home"
export CARGO_ENCODED_RUSTFLAGS
echo "Building tlottie Android archives"
echo " source: $tlottie_dir"
echo " rustc: $(rustc --version)"
echo " profile: $profile"
echo " features: $features"
for target_spec in \
arm64-v8a:aarch64-linux-android \
armeabi-v7a:armv7-linux-androideabi \
x86:i686-linux-android \
x86_64:x86_64-linux-android
do
abi=${target_spec%%:*}
rust_target=${target_spec#*:}
destination="$out_root/$abi/libtlottie.a"
echo "Building $abi ($rust_target)"
cargo rustc \
--manifest-path "$manifest" \
--locked \
--profile "$profile" \
--target "$rust_target" \
--lib \
--no-default-features \
--features "$features" \
--crate-type staticlib \
-- \
-C metadata=tlottie-staticlib
artifact="$target_dir/$rust_target/$profile/libtlottie.a"
if [ ! -f "$artifact" ]; then
echo "error: cargo did not emit $artifact" >&2
exit 1
fi
if [ ! -d "$out_root/$abi" ]; then
echo "error: output directory does not exist: $out_root/$abi" >&2
exit 1
fi
# Copy through a file in the destination directory so replacement is atomic.
tmp=$(mktemp "$out_root/$abi/.libtlottie.a.XXXXXX")
cp "$artifact" "$tmp"
chmod 0644 "$tmp"
mv -f "$tmp" "$destination"
# The container runs as root, so without this the archive would land in
# the host checkout owned by root on native Linux hosts. HOST_UID/GID are
# passed in by the top-level build.sh.
if [ -n "${HOST_UID:-}" ] && [ -n "${HOST_GID:-}" ]; then
chown "$HOST_UID:$HOST_GID" "$destination"
fi
bytes=$(wc -c < "$destination" | tr -d ' ')
echo "Wrote $destination ($bytes bytes)"
done
echo "All tlottie Android archives are ready."

Binary file not shown.

Binary file not shown.

View file

@ -1,117 +0,0 @@
#!/bin/sh
set -eu
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
tlottie_dir=${TLOTTIE_SOURCE_DIR:-"$script_dir/../tlottie"}
manifest="$tlottie_dir/Cargo.toml"
profile=release-nostd
features=cpu,no-std,c-api
if [ ! -f "$manifest" ]; then
echo "error: tlottie Cargo.toml not found at $manifest" >&2
echo "set TLOTTIE_SOURCE_DIR if the source is not next to tlottie_lib" >&2
exit 1
fi
rustup_toolchain=
if command -v rustup >/dev/null 2>&1; then
rustup_toolchain=${TLOTTIE_RUST_TOOLCHAIN:-stable}
fi
run_cargo() {
if [ -n "$rustup_toolchain" ]; then
rustup run "$rustup_toolchain" cargo "$@"
else
cargo "$@"
fi
}
run_rustc() {
if [ -n "$rustup_toolchain" ]; then
rustup run "$rustup_toolchain" rustc "$@"
else
rustc "$@"
fi
}
if [ -n "$rustup_toolchain" ]; then
missing_targets=
for target in \
aarch64-linux-android \
armv7-linux-androideabi \
i686-linux-android \
x86_64-linux-android
do
if ! rustup target list --toolchain "$rustup_toolchain" --installed | grep -qx "$target"; then
missing_targets="$missing_targets $target"
fi
done
if [ -n "$missing_targets" ]; then
echo "error: Rust Android targets are not installed:$missing_targets" >&2
echo "install them with: rustup target add --toolchain $rustup_toolchain$missing_targets" >&2
exit 1
fi
fi
target_dir=${CARGO_TARGET_DIR:-"$tlottie_dir/target/no-std-android"}
export CARGO_TARGET_DIR="$target_dir"
echo "Building tlottie Android archives"
echo " source: $tlottie_dir"
echo " rustc: $(run_rustc --version)"
echo " profile: $profile"
echo " features: $features"
echo " target dir: $target_dir"
temporary_archive=
cleanup() {
if [ -n "$temporary_archive" ] && [ -f "$temporary_archive" ]; then
unlink "$temporary_archive"
fi
}
trap cleanup EXIT HUP INT TERM
for target_spec in \
arm64-v8a:aarch64-linux-android \
armeabi-v7a:armv7-linux-androideabi \
x86:i686-linux-android \
x86_64:x86_64-linux-android
do
abi=${target_spec%%:*}
rust_target=${target_spec#*:}
destination="$script_dir/$abi/libtlottie.a"
echo "Building $abi ($rust_target)"
run_cargo rustc \
--manifest-path "$manifest" \
--locked \
--profile "$profile" \
--target "$rust_target" \
--lib \
--no-default-features \
--features "$features" \
--crate-type staticlib
artifact="$target_dir/$rust_target/$profile/libtlottie.a"
if [ ! -f "$artifact" ]; then
echo "error: Cargo did not emit $artifact" >&2
exit 1
fi
if [ ! -d "$script_dir/$abi" ]; then
echo "error: output directory does not exist: $script_dir/$abi" >&2
exit 1
fi
# Copy through a file in the destination directory so replacement is atomic.
temporary_archive=$(mktemp "$script_dir/$abi/.libtlottie.a.XXXXXX")
cp "$artifact" "$temporary_archive"
chmod 0644 "$temporary_archive"
mv -f "$temporary_archive" "$destination"
temporary_archive=
bytes=$(wc -c < "$destination" | tr -d ' ')
echo "Wrote $destination ($bytes bytes)"
done
echo "All tlottie Android archives are ready."

View file

@ -74,133 +74,10 @@ elseif(${ANDROID_ABI} STREQUAL "x86_64")
HAVE_SSE2)
endif()
#openh264
add_library(openh264 STATIC
third_party/openh264/src/codec/encoder/core/src/au_set.cpp
third_party/openh264/src/codec/encoder/core/src/deblocking.cpp
third_party/openh264/src/codec/encoder/core/src/decode_mb_aux.cpp
third_party/openh264/src/codec/encoder/core/src/encode_mb_aux.cpp
third_party/openh264/src/codec/encoder/core/src/encoder_data_tables.cpp
third_party/openh264/src/codec/encoder/core/src/encoder_ext.cpp
third_party/openh264/src/codec/encoder/core/src/encoder.cpp
third_party/openh264/src/codec/encoder/core/src/get_intra_predictor.cpp
third_party/openh264/src/codec/encoder/core/src/md.cpp
third_party/openh264/src/codec/encoder/core/src/mv_pred.cpp
third_party/openh264/src/codec/encoder/core/src/nal_encap.cpp
third_party/openh264/src/codec/encoder/core/src/paraset_strategy.cpp
third_party/openh264/src/codec/encoder/core/src/picture_handle.cpp
third_party/openh264/src/codec/encoder/core/src/ratectl.cpp
third_party/openh264/src/codec/encoder/core/src/ref_list_mgr_svc.cpp
third_party/openh264/src/codec/encoder/core/src/sample.cpp
third_party/openh264/src/codec/encoder/core/src/set_mb_syn_cabac.cpp
third_party/openh264/src/codec/encoder/core/src/set_mb_syn_cavlc.cpp
third_party/openh264/src/codec/encoder/core/src/slice_multi_threading.cpp
third_party/openh264/src/codec/encoder/core/src/svc_base_layer_md.cpp
third_party/openh264/src/codec/encoder/core/src/svc_enc_slice_segment.cpp
third_party/openh264/src/codec/encoder/core/src/svc_encode_mb.cpp
third_party/openh264/src/codec/encoder/core/src/svc_encode_slice.cpp
third_party/openh264/src/codec/encoder/core/src/svc_mode_decision.cpp
third_party/openh264/src/codec/encoder/core/src/svc_motion_estimate.cpp
third_party/openh264/src/codec/encoder/core/src/svc_set_mb_syn_cabac.cpp
third_party/openh264/src/codec/encoder/core/src/svc_set_mb_syn_cavlc.cpp
third_party/openh264/src/codec/encoder/core/src/wels_preprocess.cpp
third_party/openh264/src/codec/encoder/core/src/wels_task_base.cpp
third_party/openh264/src/codec/encoder/core/src/wels_task_encoder.cpp
third_party/openh264/src/codec/encoder/core/src/wels_task_management.cpp
third_party/openh264/src/codec/encoder/plus/src/welsEncoderExt.cpp
third_party/openh264/src/codec/common/src/welsCodecTrace.cpp
third_party/openh264/src/codec/common/src/common_tables.cpp
third_party/openh264/src/codec/common/src/copy_mb.cpp
third_party/openh264/src/codec/common/src/cpu.cpp
third_party/openh264/src/codec/common/src/crt_util_safe_x.cpp
third_party/openh264/src/codec/common/src/deblocking_common.cpp
third_party/openh264/src/codec/common/src/expand_pic.cpp
third_party/openh264/src/codec/common/src/intra_pred_common.cpp
third_party/openh264/src/codec/common/src/mc.cpp
third_party/openh264/src/codec/common/src/memory_align.cpp
third_party/openh264/src/codec/common/src/sad_common.cpp
third_party/openh264/src/codec/common/src/WelsTaskThread.cpp
third_party/openh264/src/codec/common/src/WelsThread.cpp
third_party/openh264/src/codec/common/src/WelsThreadLib.cpp
third_party/openh264/src/codec/common/src/WelsThreadPool.cpp
third_party/openh264/src/codec/common/src/utils.cpp
third_party/openh264/src/codec/processing/src/adaptivequantization/AdaptiveQuantization.cpp
third_party/openh264/src/codec/processing/src/backgrounddetection/BackgroundDetection.cpp
third_party/openh264/src/codec/processing/src/common/memory.cpp
third_party/openh264/src/codec/processing/src/common/WelsFrameWork.cpp
third_party/openh264/src/codec/processing/src/common/WelsFrameWorkEx.cpp
third_party/openh264/src/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp
third_party/openh264/src/codec/processing/src/denoise/denoise.cpp
third_party/openh264/src/codec/processing/src/denoise/denoise_filter.cpp
third_party/openh264/src/codec/processing/src/downsample/downsample.cpp
third_party/openh264/src/codec/processing/src/downsample/downsamplefuncs.cpp
third_party/openh264/src/codec/processing/src/imagerotate/imagerotate.cpp
third_party/openh264/src/codec/processing/src/imagerotate/imagerotatefuncs.cpp
third_party/openh264/src/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp
third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetection.cpp
third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetectionFuncs.cpp
third_party/openh264/src/codec/processing/src/vaacalc/vaacalcfuncs.cpp
third_party/openh264/src/codec/processing/src/vaacalc/vaacalculation.cpp)
target_compile_options(openh264 PUBLIC
-Wall -finline-functions -fno-strict-aliasing -O3 -frtti -Wno-unknown-pragmas -funroll-loops -fexceptions -fno-math-errno)
#openh264 (prebuilt static library)
add_library(openh264 STATIC IMPORTED)
set_target_properties(openh264 PROPERTIES
ANDROID_ARM_MODE arm)
target_compile_definitions(openh264 PRIVATE
)
target_compile_definitions(openh264 PUBLIC
)
target_include_directories(openh264 PUBLIC
third_party/openh264/src/codec/encoder/core/inc
third_party/openh264/src/codec/encoder/plus/inc
third_party/openh264/src/codec/decoder/plus/inc
third_party/openh264/src/codec/common/inc
third_party/openh264/src/codec/api/svc
third_party/openh264/src/codec/processing/interface
third_party/openh264/src/codec/processing/src/common)
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
target_sources(openh264 PRIVATE
third_party/openh264/src/codec/encoder/core/arm/intra_pred_neon.S
third_party/openh264/src/codec/encoder/core/arm/intra_pred_sad_3_opt_neon.S
third_party/openh264/src/codec/encoder/core/arm/memory_neon.S
third_party/openh264/src/codec/encoder/core/arm/pixel_neon.S
third_party/openh264/src/codec/encoder/core/arm/reconstruct_neon.S
third_party/openh264/src/codec/encoder/core/arm/svc_motion_estimation.S
third_party/openh264/src/codec/common/arm/copy_mb_neon.S
third_party/openh264/src/codec/common/arm/deblocking_neon.S
third_party/openh264/src/codec/common/arm/expand_picture_neon.S
third_party/openh264/src/codec/common/arm/intra_pred_common_neon.S
third_party/openh264/src/codec/common/arm/mc_neon.S
third_party/openh264/src/codec/processing/src/arm/adaptive_quantization.S
third_party/openh264/src/codec/processing/src/arm/down_sample_neon.S
third_party/openh264/src/codec/processing/src/arm/pixel_sad_neon.S
third_party/openh264/src/codec/processing/src/arm/vaa_calc_neon.S)
target_include_directories(openh264 PUBLIC
third_party/openh264/src/codec/common/arm)
target_compile_definitions(openh264 PUBLIC
HAVE_NEON=1)
elseif(${ANDROID_ABI} STREQUAL "arm64-v8a")
target_sources(openh264 PRIVATE
third_party/openh264/src/codec/encoder/core/arm64/intra_pred_aarch64_neon.S
third_party/openh264/src/codec/encoder/core/arm64/intra_pred_sad_3_opt_aarch64_neon.S
third_party/openh264/src/codec/encoder/core/arm64/memory_aarch64_neon.S
third_party/openh264/src/codec/encoder/core/arm64/pixel_aarch64_neon.S
third_party/openh264/src/codec/encoder/core/arm64/reconstruct_aarch64_neon.S
third_party/openh264/src/codec/encoder/core/arm64/svc_motion_estimation_aarch64_neon.S
third_party/openh264/src/codec/common/arm64/copy_mb_aarch64_neon.S
third_party/openh264/src/codec/common/arm64/deblocking_aarch64_neon.S
third_party/openh264/src/codec/common/arm64/expand_picture_aarch64_neon.S
third_party/openh264/src/codec/common/arm64/intra_pred_common_aarch64_neon.S
third_party/openh264/src/codec/common/arm64/mc_aarch64_neon.S
third_party/openh264/src/codec/processing/src/arm64/adaptive_quantization_aarch64_neon.S
third_party/openh264/src/codec/processing/src/arm64/down_sample_aarch64_neon.S
third_party/openh264/src/codec/processing/src/arm64/pixel_sad_aarch64_neon.S
third_party/openh264/src/codec/processing/src/arm64/vaa_calc_aarch64_neon.S)
target_include_directories(openh264 PUBLIC
third_party/openh264/src/codec/common/arm64)
target_compile_definitions(openh264 PUBLIC
HAVE_NEON_AARCH64=1)
endif()
IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/prebuild/${ANDROID_ABI}/libopenh264.a)
#rnnoise
add_library(rnnoise STATIC

View file

@ -34,10 +34,10 @@
#include "system_wrappers/include/metrics.h"
#include "third_party/libyuv/include/libyuv/convert.h"
#include "third_party/libyuv/include/libyuv/scale.h"
#include "third_party/openh264/src/codec/api/svc/codec_api.h"
#include "third_party/openh264/src/codec/api/svc/codec_app_def.h"
#include "third_party/openh264/src/codec/api/svc/codec_def.h"
#include "third_party/openh264/src/codec/api/svc/codec_ver.h"
#include "third_party/openh264/codec/api/wels/codec_app_def.h"
#include "third_party/openh264/codec/api/wels/codec_api.h"
#include "third_party/openh264/codec/api/wels/codec_def.h"
#include "third_party/openh264/codec/api/wels/codec_ver.h"
namespace webrtc {

View file

@ -34,7 +34,7 @@
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "modules/video_coding/svc/scalable_video_controller.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "third_party/openh264/src/codec/api/svc/codec_app_def.h"
#include "third_party/openh264/codec/api/wels/codec_app_def.h"
class ISVCEncoder;

View file

@ -0,0 +1,224 @@
package org.telegram.messenger;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import org.telegram.ui.Components.ForegroundDetector;
public class ANRDetector implements ForegroundDetector.Listener {
private static final long TIMEOUT_MS = 5000;
private static final int MSG_UI_PING = 1;
private final Object lock = new Object();
private final Handler mainHandler;
private final Thread detectorThread;
private final Runnable anrDetected;
private volatile boolean foreground;
private volatile boolean destroyed;
/**
* Changes on every foreground/background transition.
*/
private volatile int generation;
/**
* Monotonically increasing id of each UI ping.
*/
private int nextPingId;
/**
* Last ping actually executed by the main thread.
*/
private volatile int acknowledgedPingId = -1;
/**
* Prevents reporting the same freeze repeatedly.
*
* Reset only after the main thread becomes responsive again.
*/
private volatile boolean anrReported;
public ANRDetector(Runnable anrDetected) {
this.anrDetected = anrDetected;
mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what != MSG_UI_PING) {
return;
}
acknowledgedPingId = msg.arg1;
/*
* If we previously detected an ANR, execution of this
* message means that the UI thread has recovered.
*/
anrReported = false;
}
};
ForegroundDetector foregroundDetector = ForegroundDetector.getInstance();
foreground = foregroundDetector.isForeground();
foregroundDetector.addListener(this);
detectorThread = new Thread(this::run, "ANRDetector");
detectorThread.start();
}
private void run() {
while (true) {
final int checkGeneration;
final int pingId;
synchronized (lock) {
/*
* Do absolutely nothing while the application is in
* background.
*/
while (!foreground && !destroyed) {
try {
lock.wait();
} catch (InterruptedException ignore) {
}
}
if (destroyed) {
return;
}
checkGeneration = generation;
pingId = ++nextPingId;
}
/*
* Post a ping to the main thread.
*/
Message message = mainHandler.obtainMessage(
MSG_UI_PING,
pingId,
checkGeneration
);
message.sendToTarget();
try {
Thread.sleep(TIMEOUT_MS);
} catch (InterruptedException ignore) {
/*
* Usually means foreground/background transition
* or destroy().
*/
continue;
}
if (destroyed) {
return;
}
/*
* Ignore this check if application state changed while
* we were waiting.
*/
if (!foreground || generation != checkGeneration) {
continue;
}
/*
* Main thread processed our ping in time.
*/
if (acknowledgedPingId == pingId) {
continue;
}
/*
* UI thread did not process the ping within TIMEOUT_MS.
*
* Report only once until the UI actually recovers.
*/
if (!anrReported) {
anrReported = true;
try {
anrDetected.run();
} catch (Throwable e) {
FileLog.e(e);
}
}
}
}
@Override
public void onBecameForeground() {
synchronized (lock) {
if (destroyed) {
return;
}
generation++;
foreground = true;
/*
* A previous ANR belongs to the previous foreground
* session.
*/
anrReported = false;
lock.notifyAll();
}
/*
* Interrupt any timeout that may belong to an old generation.
*/
detectorThread.interrupt();
}
@Override
public void onBecameBackground() {
synchronized (lock) {
if (destroyed) {
return;
}
generation++;
foreground = false;
}
/*
* Old UI pings are no longer interesting.
*/
mainHandler.removeMessages(MSG_UI_PING);
/*
* Wake the detector from Thread.sleep() immediately so it can
* enter lock.wait() and consume no periodic CPU in background.
*/
detectorThread.interrupt();
}
public void destroy() {
synchronized (lock) {
if (destroyed) {
return;
}
destroyed = true;
foreground = false;
generation++;
lock.notifyAll();
}
ForegroundDetector.getInstance().removeListener(this);
mainHandler.removeMessages(MSG_UI_PING);
detectorThread.interrupt();
}
}

View file

@ -6693,6 +6693,10 @@ public class AndroidUtilities {
return false;
}
public static String getHelloWorld() {
return "Hello World!";
}
public static String getBuildVersionInfo() {
try {
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);

View file

@ -289,7 +289,11 @@ public class ApplicationLoader extends Application {
super.onCreate();
// AndroidUtilities must be initialized before FileLog
final String helloWorld = AndroidUtilities.getHelloWorld();
if (BuildVars.LOGS_ENABLED) {
FileLog.d(helloWorld);
FileLog.d("app start time = " + (startTime = SystemClock.elapsedRealtime()));
try {
final PackageInfo info = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
@ -335,6 +339,10 @@ public class ApplicationLoader extends Application {
}
}
};
if (BuildConfig.DEBUG_VERSION) {
new ANRDetector(FileLog::dumpANR);
}
if (BuildVars.LOGS_ENABLED) {
FileLog.d("load libs time = " + (SystemClock.elapsedRealtime() - startTime));
}

View file

@ -18,8 +18,8 @@ import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.PendingPurchasesParams;
import com.android.billingclient.api.ProductDetails;
import com.android.billingclient.api.ProductDetailsResponseListener;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesResponseListener;
import com.android.billingclient.api.PurchasesUpdatedListener;
@ -79,7 +79,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
private BillingController(Context ctx) {
billingClient = BillingClient.newBuilder(ctx)
.enablePendingPurchases()
.enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
.setListener(this)
.build();
}
@ -160,7 +160,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
return;
}
billingClientEmpty = true;
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.billingProductDetailsUpdated);
NotificationCenter.getGlobalInstance().postNotificationNameOnUIThread(NotificationCenter.billingProductDetailsUpdated);
}
private void switchBackFromInvoice() {
@ -168,18 +168,23 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien
return;
}
billingClientEmpty = false;
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.billingProductDetailsUpdated);
NotificationCenter.getGlobalInstance().postNotificationNameOnUIThread(NotificationCenter.billingProductDetailsUpdated);
}
public boolean isReady() {
return billingClient.isReady();
}
public void queryProductDetails(List<QueryProductDetailsParams.Product> products, ProductDetailsResponseListener responseListener) {
public interface ProductDetailsResponseListenerLegacy {
void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> list);
}
public void queryProductDetails(List<QueryProductDetailsParams.Product> products, ProductDetailsResponseListenerLegacy responseListener) {
if (!isReady()) {
throw new IllegalStateException("Billing: Controller should be ready for this call!");
}
billingClient.queryProductDetailsAsync(QueryProductDetailsParams.newBuilder().setProductList(products).build(), responseListener);
billingClient.queryProductDetailsAsync(QueryProductDetailsParams.newBuilder().setProductList(products).build(), (billingResult, queryProductDetailsResult) ->
responseListener.onProductDetailsResponse(billingResult, queryProductDetailsResult.getProductDetailsList()));
}
/**

View file

@ -293,10 +293,37 @@ public class BotForumHelper extends BaseController {
public boolean hasBotForumDrafts(long userId, int topicId) {
LongSparseArray<BotDraftMessage> messages = botTextDraftsByRandomIds.get(userId, topicId);
return messages != null && messages.size() > 0;
if (messages != null && messages.size() > 0) {
for (int a = 0, N = messages.size(); a < N; a++) {
if (!messages.valueAt(a).removed) {
return true;
}
}
}
return false;
}
public void removeAllMarkedAsRemovedMessages(long userId, int topicId) {
LongSparseArray<BotDraftMessage> messages = botTextDraftsByRandomIds.get(userId, topicId);
if (messages == null) {
return;
}
for (int a = 0, N = messages.size(); a < N; a++) {
BotDraftMessage draftMessage = messages.valueAt(a);
if (draftMessage.removed) {
getNotificationCenter().postNotificationName(NotificationCenter.botForumDraftDelete,
new BotForumTextDraftDeleteNotification(userId, topicId, draftMessage.localMessageId));
botTextDraftsByRandomIds.remove(userId, topicId, draftMessage.randomId);
a--;
N--;
}
}
}
public MessageObject onBotForumDraftCheckNewMessages(long userId, int topicId, int messageId, String message) {
removeAllMarkedAsRemovedMessages(userId, topicId);
LongSparseArray<BotDraftMessage> messages = botTextDraftsByRandomIds.get(userId, topicId);
if (messages == null) {
return null;

View file

@ -55,6 +55,7 @@ public class FileLog {
private File networkFile = null;
private File tonlibFile = null;
private boolean initied;
private boolean initiing;
public static boolean databaseIsMalformed = false;
private OutputStreamWriter tlStreamWriter = null;
@ -71,17 +72,17 @@ public class FileLog {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new FileLog();
if (BuildVars.LOGS_ENABLED) {
localInstance.init();
}
}
}
}
return localInstance;
}
public FileLog() {
if (!BuildVars.LOGS_ENABLED) {
return;
}
init();
private FileLog() {
}
@ -297,10 +298,17 @@ public class FileLog {
}
public void init() {
private void init() {
if (initied) {
return;
}
if (initiing) {
if (BuildConfig.DEBUG_PRIVATE_VERSION) {
throw new IllegalStateException("double init call");
}
}
initiing = true;
dateFormat = FastDateFormat.getInstance("dd_MM_yyyy_HH_mm_ss.SSS", Locale.US);
fileDateFormat = FastDateFormat.getInstance("dd_MM_yyyy_HH_mm_ss", Locale.US);
String date = fileDateFormat.format(System.currentTimeMillis());
@ -329,9 +337,6 @@ public class FileLog {
} catch (Exception e) {
e.printStackTrace();
}
if (BuildVars.DEBUG_VERSION) {
new ANRDetector(this::dumpANR);
}
initied = true;
}
@ -483,7 +488,7 @@ public class FileLog {
}
}
private void dumpANR() {
public static void dumpANR() {
StringBuilder sb = new StringBuilder();
Map<Thread, StackTraceElement[]> allThreads = Thread.getAllStackTraces();
@ -499,7 +504,7 @@ public class FileLog {
}
FileLog.e("ANR thread dump\n" + sb.toString());
dumpMemory(false);
getInstance().dumpMemory(false);
}
public static void fatal(final Throwable e, boolean logToAppCenter) {
@ -624,31 +629,4 @@ public class FileLog {
}
}
public class ANRDetector {
private final long TIMEOUT_MS = 5000; // ANR threshold (5 seconds)
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private boolean isUIThreadResponsive = true;
public ANRDetector(Runnable anrDetected) {
new Thread(() -> {
while (true) {
isUIThreadResponsive = false;
// Post a task to the main thread
mainHandler.post(() -> isUIThreadResponsive = true);
try {
Thread.sleep(TIMEOUT_MS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!isUIThreadResponsive) {
anrDetected.run();
}
}
}).start();
}
}
}

View file

@ -10131,6 +10131,9 @@ public class MessageObject {
}
public boolean canSetReaction() {
if (isEphemeral()) {
return false;
}
if (messageOwner instanceof TLRPC.TL_messageService)
return messageOwner.reactions_are_possible;
return true;

View file

@ -154,6 +154,7 @@ public class RichMessageLayout {
private static final int ORDERED_LIST_MARKER_START_DP = 6;
public final ArrayList<RichUnsupportedBlock> unsupportedBlocks = new ArrayList<>();
public final ArrayList<RichUnsupportedBlock> unsupportedBlocksRoot = new ArrayList<>();
public final ArrayList<RichBlock> blocks = new ArrayList<>();
public final ArrayList<QuoteBackground> quotes = new ArrayList<>();
private Drawable pullquoteIcon;
@ -353,6 +354,7 @@ public class RichMessageLayout {
}
unsupportedBlocks.clear();
unsupportedBlocksRoot.clear();
blocks.clear();
quotes.clear();
anchors.clear();
@ -1144,11 +1146,15 @@ public class RichMessageLayout {
}
return null;
} else if (pageBlock instanceof TL_iv.pageBlockUnsupported) {
final int o = BitwiseUtils.hasFlag(textFlags, TEXT_FLAG_BLOCK_QUOTE) ? dp(6) : level > 0 ? dp(4) : 0;
final RichUnsupportedBlock block = new RichUnsupportedBlock(this, new Rect(
-dp(7), Math.max(dp(14), padding.top),
-dp(7), Math.max(dp(14), padding.bottom)
), maxWidth, blocks.size());
padding.left + o - dp(7), Math.max(dp(14), padding.top),
padding.right + o - dp(7), Math.max(dp(14), padding.bottom)
), maxWidth, blocks.size(), level);
unsupportedBlocks.add(block);
if (level == 0) {
unsupportedBlocksRoot.add(block);
}
blocks.add(block);
return block;
} else if (pageBlock instanceof TL_iv.pageBlockDetails) {
@ -1210,10 +1216,19 @@ public class RichMessageLayout {
return !unsupportedBlocks.isEmpty();
}
public boolean hasRootUnsupportedBlocks() {
return !unsupportedBlocksRoot.isEmpty();
}
public ArrayList<RichUnsupportedBlock> getUnsupportedHoles() {
return unsupportedBlocks;
}
public ArrayList<RichUnsupportedBlock> getUnsupportedHolesRoot() {
return unsupportedBlocksRoot;
}
public int getMinWidth() {
return minWidth;
}
@ -2766,6 +2781,31 @@ public class RichMessageLayout {
private int pressedLinkStart, pressedLinkEnd;
private AnimatedEmojiSpan pressedEmoji;
private RichButtonSpan pressedButtonSpan;
private final RectF soleButtonHitBounds = new RectF();
private RichButtonSpan getSoleButtonSpan() {
if (!(layout.getText() instanceof Spanned)) return null;
final Spanned text = (Spanned) layout.getText();
final RichButtonSpan[] spans = text.getSpans(0, text.length(), RichButtonSpan.class);
if (spans.length != 1) return null;
final int spanStart = text.getSpanStart(spans[0]);
final int spanEnd = text.getSpanEnd(spans[0]);
for (int i = 0; i < text.length(); i++) {
if ((i < spanStart || i >= spanEnd) && !Character.isWhitespace(text.charAt(i))) {
return null;
}
}
return spans[0];
}
private void setSoleButtonHitBounds(float left, float top, float right, float bottom) {
soleButtonHitBounds.set(left, top, right, bottom);
}
private boolean buttonContains(RichButtonSpan span, float x, float y) {
return span.contains(x, y, dp(8))
|| (span == getSoleButtonSpan() && soleButtonHitBounds.contains(x, y));
}
public boolean onTouchEvent(MotionEvent event) {
final int act = event.getActionMasked();
@ -2789,7 +2829,7 @@ public class RichMessageLayout {
final RichButtonSpan[] buttonSpans = getButtonSpans();
if (buttonSpans != null) {
for (RichButtonSpan span : buttonSpans) {
if (span.contains(lx, ly)) {
if (buttonContains(span, lx, ly)) {
if (span.isDisabled()) {
return true;
}
@ -2891,7 +2931,7 @@ public class RichMessageLayout {
if (act == MotionEvent.ACTION_MOVE) {
if (pressedButtonSpan != null) {
// drop the press once the finger leaves the pill, same as a bot button row
if (!pressedButtonSpan.contains(lx, ly)) {
if (!buttonContains(pressedButtonSpan, lx, ly)) {
cancelLongPress();
pressedButtonSpan.setPressed(false);
pressedButtonSpan = null;
@ -4479,6 +4519,11 @@ public class RichMessageLayout {
pressedCellText = (Text) cell.textLayout;
cellDx = cell.getTextX() - scrollX;
cellDy = titleHeight + cell.getTextY();
pressedCellText.setSoleButtonHitBounds(
cell.x - cell.getTextX(), cell.y - cell.getTextY(),
cell.x + cell.getMeasuredWidth() - cell.getTextX(),
cell.y + cell.getMeasuredHeight() - cell.getTextY()
);
event.offsetLocation(-cellDx, -cellDy);
textHandlingTouch = pressedCellText.onTouchEvent(event);
event.offsetLocation(cellDx, cellDy);
@ -4704,13 +4749,15 @@ public class RichMessageLayout {
public final int unsupportedBlockWidth;
public final int unsupportedBlockHeight;
public final int index;
public final int level;
public TornEdge.Params tornParams;
public Bitmap tornBitmap;
public RichUnsupportedBlock(RichMessageLayout root, Rect padding, int maxWidth, int index) {
public RichUnsupportedBlock(RichMessageLayout root, Rect padding, int maxWidth, int index, int level) {
super(root, padding, maxWidth);
this.index = index;
this.level = level;
unsupportedBlockDrawable = new UnsupportedBlockDrawable(root.resourcesProvider);
unsupportedBlockDrawable.setCallback(this);
@ -5737,6 +5784,11 @@ public class RichMessageLayout {
return bounds.contains(x, y);
}
public boolean contains(float x, float y, float padding) {
return x >= bounds.left - padding && x < bounds.right + padding
&& y >= bounds.top - padding && y < bounds.bottom + padding;
}
public void setPressed(boolean pressed) {
button.setPressed(pressed);
}

View file

@ -4,6 +4,7 @@ import android.text.TextUtils;
import androidx.annotation.Nullable;
import org.telegram.tgnet.NativeByteBuffer;
import org.telegram.tgnet.TLObject;
import org.telegram.messenger.MediaDataController;
@ -277,4 +278,49 @@ public class TlUtils {
poll.shuffled_answers.sort((a1, a2) -> Long.compareUnsigned(a1.shuffle_hash, a2.shuffle_hash));
}
}
public static boolean tlEquals(TLObject object1, TLObject object2) {
if (object1 == object2) {
return true;
}
if (object1 == null || object2 == null) {
return false;
}
final int size1 = object1.getObjectSize();
final int size2 = object2.getObjectSize();
if (size1 != size2) {
return false;
}
try {
NativeByteBuffer data1 = new NativeByteBuffer(size1);
object1.serializeToStream(data1);
data1.rewind();
NativeByteBuffer data2 = new NativeByteBuffer(size2);
object2.serializeToStream(data2);
data2.rewind();
int remaining = size1;
while (remaining >= 8) {
if (data1.readInt64(true) != data2.readInt64(true)) {
return false;
}
remaining -= 8;
}
while (remaining > 0) {
if (data1.readByte(true) != data2.readByte(true)) {
return false;
}
remaining--;
}
return true;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View file

@ -71,6 +71,7 @@ import org.telegram.ui.Components.SnowflakesEffect;
import org.telegram.ui.Components.blur3.BlurredBackgroundDrawableViewFactory;
import org.telegram.ui.Components.blur3.drawable.BlurredBackgroundDrawable;
import org.telegram.ui.Components.blur3.drawable.color.BlurredBackgroundColorProvider;
import org.telegram.ui.MainTabsLayout;
import java.util.ArrayList;
@ -1859,6 +1860,47 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
return castShadows;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (chatAvatarContainer != null && glassMode) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
final int x = (int) ev.getX();
final int y = (int) ev.getY();
View child = findChildUnder(this, x, y, chatAvatarContainer);
if (child == null) {
child = findChildUnder(this, x, y, null);
}
boolean contains = false;
contains |= glassDrawable != null && glassDrawable.getBounds().contains(x, y);
if (child != null && child != chatAvatarContainer) {
contains |= glassDrawableBack != null && glassDrawableBack.getBounds().contains(x, y);
contains |= glassDrawableMenu != null && glassDrawableMenu.getBounds().contains(x, y);
}
if (!contains) {
return false;
}
}
}
return super.dispatchTouchEvent(ev);
}
public static View findChildUnder(ViewGroup parent, float x, float y, View exclude) {
for (int i = parent.getChildCount() - 1; i >= 0; i--) {
View child = parent.getChildAt(i);
if (child.getVisibility() != View.VISIBLE || child == exclude) continue;
if (x >= child.getX() && x <= (child.getX() + child.getWidth())
&& y >= child.getTop() && y <= child.getBottom()) {
return child;
}
}
return null;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (forceSkipTouches) {
@ -2110,7 +2152,7 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
final boolean hasAvatar = chatAvatarContainer.hasVisibleAvatar();
int visualWidth = chatAvatarContainer.getVisualWidth();
if (hasAvatar) {
visualWidth = Math.max(visualWidth, dp(192));
//visualWidth = Math.max(visualWidth, dp(168));
}
final int width = Math.min(getMeasuredWidth() - dp(6 + 46 + 6 + 6 + 46 + 6), visualWidth);
@ -2136,7 +2178,9 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
}
private int forcedMenuWidth;
private int forcedMenuMinWidth;
private boolean hasForcedMenuWidth;
private boolean hasForcedMenuMinWidth;
public void setForcedMenuWidth(int width) {
hasForcedMenuWidth = true;
@ -2146,6 +2190,14 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
}
}
public void setForcedMenuMinWidth(int width) {
hasForcedMenuMinWidth = true;
if (forcedMenuMinWidth != width) {
forcedMenuMinWidth = width;
invalidate();
}
}
private boolean isAnimationsAllowed;
public void checkMenuItemsWidth() {
@ -2172,7 +2224,8 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
final int s = dp(46);
final float actionModeFactor = getActionModeFactor();
final int menuWidth = hasForcedMenuWidth ? forcedMenuWidth : (int) animatorMenuItemsWidth.getFactor();
final int menuWidthA = hasForcedMenuWidth ? forcedMenuWidth : (int) animatorMenuItemsWidth.getFactor();
final int menuWidth = hasForcedMenuMinWidth ? Math.max((int) (forcedMenuMinWidth * (1f - searchFactor)), menuWidthA) : menuWidthA;
final boolean hasBackButton = backButtonImageView != null && backButtonImageView.getVisibility() == View.VISIBLE;
@ -2180,7 +2233,7 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
final int b = t + s + p * 2;
if (glassDrawable != null && !glassOnlyBack) {
final int menuWidthWithPadding = menuWidth + (hasForcedMenuWidth ? (menuWidth > 0 ? p : 0) : (int) (p * animatorHasMenuItems.getFloatValue()));
final int menuWidthWithPadding = menuWidth + ((hasForcedMenuWidth || hasForcedMenuMinWidth) ? (menuWidth > 0 ? p : 0) : (int) (p * animatorHasMenuItems.getFloatValue()));
final int rightOffset = lerp(menuWidthWithPadding, Math.max(menuWidthWithPadding, p + s), chatAvatarContainer == null ? 0f : 1f - animatorAvatarContainerHasAvatar.getFloatValue());
final int leftDefault = lerp(hasBackButton ? s + p : 0, s + p, chatAvatarContainer == null? 0f : 1f - animatorAvatarContainerHasAvatar.getFloatValue());
@ -2191,10 +2244,13 @@ public class ActionBar extends FrameLayout implements FactorAnimator.Target, The
final int width = lerp(Math.min(widthDefault, (int) animatorAvatarContainerWidth.getFactor() + p * 2), widthDefault, Math.max(searchFactor, actionModeFactor));
left = (rightDefault + leftDefault - width) / 2;
right = left + width;
chatAvatarContainer.setTranslationX(left
final float translationX = left
- ((MarginLayoutParams)(chatAvatarContainer.getLayoutParams())).leftMargin
- chatAvatarContainer.getLeftPadding()
+ p + dp(3));
+ p + dp(3);
chatAvatarContainer.setTranslationX(translationX);
chatAvatarContainer.setPivotX((chatAvatarContainer.getMeasuredWidth()) / 2f - translationX );
} else {
left = leftDefault;
right = rightDefault;

View file

@ -12059,7 +12059,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
flagSecure = new FlagSecureReason(window, () ->
currentMessageObject != null && currentMessageObject.messageOwner != null && (
currentMessageObject.type == MessageObject.TYPE_PAID_MEDIA && (groupMedia == null || !groupMedia.hidden) ||
currentMessageObject.messageOwner.noforwards ||
currentMessageObject.messageOwner.noforwards && !currentMessageObject.isEphemeral() ||
currentMessageObject.isVoiceOnce() ||
currentMessageObject.hasRevealedExtendedMedia()
)
@ -20377,12 +20377,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
final boolean hasUnsupportedBlocks = currentMessageObject.richLayout != null && currentMessageObject.richLayout.hasUnsupportedBlocks();
final boolean hasRootUnsupportedBlocks = currentMessageObject.richLayout != null && currentMessageObject.richLayout.hasRootUnsupportedBlocks();
ArrayList<RichMessageLayout.RichUnsupportedBlock> holes = null;
ArrayList<RichMessageLayout.RichUnsupportedBlock> holesRoot = null;
if (!internal && hasUnsupportedBlocks) {
holes = currentMessageObject.richLayout.getUnsupportedHoles();
holesRoot = currentMessageObject.richLayout.getUnsupportedHolesRoot();
}
if (!internal && hasUnsupportedBlocks && holes != null && !holes.isEmpty()) {
if (!internal && hasRootUnsupportedBlocks && holes != null && !holes.isEmpty()) {
//if (transitionParams != null && transitionParams.animateChange || currentMessageObject.richLayout.blockquoteAnimating || currentMessageObject.richLayout.detailsAnimating) {
layoutTextXY(false);
//}
@ -20391,8 +20394,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
boolean result = false;
int bY = 0;
for (int a = 0, N = holes.size(); a <= N; a++) {
RichMessageLayout.RichUnsupportedBlock hole = a < N ? holes.get(a) : null;
for (int a = 0, N = holesRoot.size(); a <= N; a++) {
RichMessageLayout.RichUnsupportedBlock hole = a < N ? holesRoot.get(a) : null;
canvas.save();
if (hole != null) {
canvas.clipRect(0, a == 0 ? Integer.MIN_VALUE : textY + bY, getWidth(), textY + (int) hole.getY(transitionParams));
@ -20449,24 +20452,25 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (drawBackground) {
for (int a = 0, N = holes.size(); a < N; a++) {
RichMessageLayout.RichUnsupportedBlock hole = holes.get(a);
final int tornWidth = backgroundRight - backgroundLeft;
if (hole.tornBitmap == null || hole.tornBitmap.getWidth() < tornWidth) {
hole.tornParams = new TornEdge.Params();
hole.tornBitmap = TornEdge.createTearBitmap(hole.tornParams, tornWidth,
currentMessageObject.getId() * 100 + hole.index);
}
final RichMessageLayout.RichUnsupportedBlock hole = holes.get(a);
final float t = textY + hole.getY(transitionParams);
final float b = t + hole.getHeight(transitionParams);
canvas.save();
canvas.clipRect(backgroundLeft, 0, backgroundRight, getHeight());
TornEdge.drawTopEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, t, paint);
TornEdge.drawBottomEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, b, paint);
canvas.restore();
if (hole.level == 0) {
final int tornWidth = backgroundRight - backgroundLeft;
if (hole.tornBitmap == null || hole.tornBitmap.getWidth() < tornWidth) {
hole.tornParams = new TornEdge.Params();
hole.tornBitmap = TornEdge.createTearBitmap(hole.tornParams, tornWidth,
currentMessageObject.getId() * 100 + hole.index);
}
canvas.save();
canvas.clipRect(backgroundLeft, 0, backgroundRight, getHeight());
TornEdge.drawTopEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, t, paint);
TornEdge.drawBottomEdge(canvas, hole.tornBitmap, hole.tornParams, tornWidth, backgroundLeft, b, paint);
canvas.restore();
}
AndroidUtilities.rectTmp.set(
backgroundLeft + dp(3.33f), t + hole.padding.top,
backgroundRight - dp(3.33f), b - hole.padding.bottom);
backgroundLeft + (hole.padding.left + dp(7)) + dp(3.33f), t + hole.padding.top,
backgroundRight - (hole.padding.right + dp(7)) - dp(3.33f), b - hole.padding.bottom);
drawServiceBackground(canvas, AndroidUtilities.rectTmp, dp(18), 1f);
}
}

View file

@ -2058,6 +2058,7 @@ public class ChatActivity extends BaseFragment implements
@Override
public void didPressStreamingStop() {
BotForumHelper.getInstance(currentAccount).stopStreaming(dialog_id, (int) getTopicId());
checkSendButtonBlockedByTyping(true);
}
@Override
@ -4577,11 +4578,18 @@ public class ChatActivity extends BaseFragment implements
BlurredBackgroundProviderImpl.topPanelChatActivity(themeDelegate),
ChatObject.isForum(currentChat));
if (chatMode == MODE_WELCOME_MESSAGES) {
if (chatMode == MODE_PINNED) {
actionBar.setChatAvatarContainer(avatarContainer);
avatarContainer.setActionBar(actionBar);
} else if (chatMode == MODE_WELCOME_MESSAGES) {
actionBar.setChatAvatarContainer(avatarContainer);
actionBar.setForcedMenuWidth(dp(46));
actionBar.doNotDrawGlassMenu = true;
avatarContainer.setActionBar(actionBar);
} else if (isComments) {
actionBar.setChatAvatarContainer(avatarContainer);
actionBar.setForcedMenuMinWidth(dp(46));
avatarContainer.setActionBar(actionBar);
}
chatInputViewsContainer = new ChatInputViewsContainer(context);
@ -7113,7 +7121,8 @@ public class ChatActivity extends BaseFragment implements
jumpToDate((int) (calendar.getTime().getTime() / 1000));
});
if (currentChat != null) {
if (currentChat != null && chatMode != MODE_WELCOME_MESSAGES) {
// todo: only for default mode ??
pendingRequestsDelegate = new ChatActivityMemberRequestsDelegate(this, currentChat);
topPanelLayout.addView(pendingRequestsDelegate.getView(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 40));
topPanelLayout.setPriority(pendingRequestsDelegate.getView(), 3);
@ -25494,9 +25503,12 @@ public class ChatActivity extends BaseFragment implements
if (!arr.isEmpty()) {
if ((chatMode == MODE_SCHEDULED || chatMode == MODE_QUICK_REPLIES)) {
replaceMessageObjects(arr, 0, true);
} else if (UserObject.isBot(currentUser) && BotForumHelper.getInstance(currentAccount).hasBotForumDrafts(currentUser.id, (int) getTopicId())) {
replaceMessageObjects(arr, 0, false);
hasDraftsReplaces = !BotForumHelper.getInstance(currentAccount).hasBotForumDrafts(currentUser.id, (int) getTopicId());
} else if (UserObject.isBot(currentUser)) {
BotForumHelper.getInstance(currentAccount).removeAllMarkedAsRemovedMessages(currentUser.id, (int) getTopicId());
if (BotForumHelper.getInstance(currentAccount).hasBotForumDrafts(currentUser.id, (int) getTopicId())) {
replaceMessageObjects(arr, 0, false);
hasDraftsReplaces = !BotForumHelper.getInstance(currentAccount).hasBotForumDrafts(currentUser.id, (int) getTopicId());
}
}
}
@ -26083,6 +26095,20 @@ public class ChatActivity extends BaseFragment implements
scrollToTopOnResume = true;
}
}
if (chatMode == MODE_DEFAULT) {
for (MessageObject messageObject : arr) {
if (messageObject != null && !messageObject.isOut() && messageObject.messageOwner != null) {
if (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) {
if (messageObject.messageOwner.reply_markup.force_reply) {
showFieldPanelForReply(messageObject);
break;
}
}
}
}
}
if (chatMode == MODE_SCHEDULED && !arr.isEmpty()) {
MessageObject messageObject = arr.get(0);
int mid = messageObject.getId();

View file

@ -250,7 +250,13 @@ public class ChatAvatarContainer extends FrameLayout implements FactorAnimator.T
if (parentFragment == null || (parentFragment.getChatMode() != ChatActivity.MODE_QUICK_REPLIES && parentFragment.getChatMode() != ChatActivity.MODE_WELCOME_MESSAGES && parentFragment.getChatMode() != ChatActivity.MODE_EDIT_BUSINESS_LINK) && parentFragment.getChatMode() != ChatActivity.MODE_SUGGESTIONS && !parentFragment.isInBotForumMode()) {
sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(baseFragment);
}
avatarImageIsHidden = parentFragment != null && (parentFragment.isThreadChat() || parentFragment.getChatMode() == ChatActivity.MODE_PINNED || parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES || parentFragment.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES || parentFragment.getChatMode() == ChatActivity.MODE_EDIT_BUSINESS_LINK);
avatarImageIsHidden = parentFragment != null && (
parentFragment.isThreadChat() && !parentFragment.isReplyChatComment() ||
parentFragment.getChatMode() == ChatActivity.MODE_PINNED ||
parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES ||
parentFragment.getChatMode() == ChatActivity.MODE_WELCOME_MESSAGES ||
parentFragment.getChatMode() == ChatActivity.MODE_EDIT_BUSINESS_LINK
);
if (avatarImageIsHidden) {
avatarImageView.setVisibility(GONE);
}
@ -414,7 +420,7 @@ public class ChatAvatarContainer extends FrameLayout implements FactorAnimator.T
protected void dispatchDraw(Canvas canvas) {
canvas.save();
final float s = bounce.getScale(.02f);
canvas.scale(s, s, getWidth() / 2f, getHeight() - ActionBar.getCurrentActionBarHeight() / 2f);
canvas.scale(s, s, getPivotX(), getHeight() - ActionBar.getCurrentActionBarHeight() / 2f);
super.dispatchDraw(canvas);
canvas.restore();
}
@ -1719,7 +1725,7 @@ public class ChatAvatarContainer extends FrameLayout implements FactorAnimator.T
width = Math.max(width, subtitleTextView.getExactWidthIncludeDrawables());
}
if (hasVisibleAvatar()) {
width += dp(52 + 16);
width += dp(52 + 18);
} else {
width += dp(34);
}

View file

@ -1716,7 +1716,10 @@ public class FilterTabsView extends FrameLayout {
invalidated = true;
requestLayout();
allTabsWidth = 0;
findDefaultTab().setTitle(LocaleController.getString(R.string.FilterAllChats), null, false);
final FilterTabsView.Tab defaultTab = findDefaultTab();
if (defaultTab != null) {
defaultTab.setTitle(LocaleController.getString(R.string.FilterAllChats), null, false);
}
for (int b = 0; b < N; b++) {
allTabsWidth += tabs.get(b).getWidth(true) + dp(TAB_PADDING_WIDTH);
}
@ -1745,9 +1748,14 @@ public class FilterTabsView extends FrameLayout {
invalidated = true;
requestLayout();
listView.setItemAnimator(itemAnimator);
adapter.notifyDataSetChanged();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
allTabsWidth = 0;
findDefaultTab().setTitle(LocaleController.getString(R.string.FilterAllChats), null, false);
final FilterTabsView.Tab defaultTab = findDefaultTab();
if (defaultTab != null) {
defaultTab.setTitle(LocaleController.getString(R.string.FilterAllChats), null, false);
}
for (int b = 0, N = tabs.size(); b < N; b++) {
allTabsWidth += tabs.get(b).getWidth(true) + dp(TAB_PADDING_WIDTH);
}

View file

@ -30,6 +30,7 @@ import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
import org.telegram.messenger.browser.Browser;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLMethod;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.tgnet.tl.TL_ephemeral;
@ -847,7 +848,7 @@ public class ReportBottomSheet extends BottomSheet {
) {
if (context == null || messageIds == null) return;
final boolean[] done = new boolean[] { false };
final TLObject request;
final TLMethod<TLRPC.ReportResult> request;
if (stories) {
TL_stories.TL_stories_report req = new TL_stories.TL_stories_report();
req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId);
@ -872,69 +873,65 @@ public class ReportBottomSheet extends BottomSheet {
req.message = TextUtils.isEmpty(message) ? "" : message;
request = req;
}
ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> {
if (response != null) {
if (response instanceof TLRPC.TL_reportResultChooseOption || response instanceof TLRPC.TL_reportResultAddComment) {
AndroidUtilities.runOnUIThread(() -> {
final ReportBottomSheet sheet = new ReportBottomSheet(context, resourceProvider, stories, ephemeral, dialogId, messageIds);
if (response instanceof TLRPC.TL_reportResultChooseOption) {
sheet.setReportChooseOption((TLRPC.TL_reportResultChooseOption) response);
} else if (response instanceof TLRPC.TL_reportResultAddComment) {
sheet.setReportChooseOption((TLRPC.TL_reportResultAddComment) response);
}
sheet.setListener(new ReportBottomSheet.Listener() {
@Override
public void onReported() {
if (!done[0] && whenDone != null) {
done[0] = true;
whenDone.run(true);
}
AndroidUtilities.runOnUIThread(() -> {
if (LaunchActivity.getSafeLastFragment() == null) return;
final BulletinFactory bf = bulletinFactory == null ? BulletinFactory.of(LaunchActivity.getSafeLastFragment()) : bulletinFactory;
if (bf == null) return;
bf
.createSimpleBulletin(
R.raw.msg_antispam,
LocaleController.getString(R.string.ReportChatSent),
LocaleController.getString(R.string.Reported2)
)
.setDuration(Bulletin.DURATION_PROLONG)
.show();
}, 200);
}
});
sheet.setOnDismissListener(() -> {
if (!done[0] && whenDone != null) {
done[0] = true;
whenDone.run(false);
}
});
sheet.show();
});
} else if (response instanceof TLRPC.TL_reportResultReported) {
AndroidUtilities.runOnUIThread(() -> {
ConnectionsManager.getInstance(currentAccount).sendRequestTyped(request, AndroidUtilities::runOnUIThread, (response, error) -> {
if (response instanceof TLRPC.TL_reportResultChooseOption || response instanceof TLRPC.TL_reportResultAddComment) {
final ReportBottomSheet sheet = new ReportBottomSheet(context, resourceProvider, stories, ephemeral, dialogId, messageIds);
if (response instanceof TLRPC.TL_reportResultChooseOption) {
sheet.setReportChooseOption((TLRPC.TL_reportResultChooseOption) response);
} else if (response instanceof TLRPC.TL_reportResultAddComment) {
sheet.setReportChooseOption((TLRPC.TL_reportResultAddComment) response);
}
sheet.setListener(new ReportBottomSheet.Listener() {
@Override
public void onReported() {
if (!done[0] && whenDone != null) {
done[0] = true;
whenDone.run(true);
}
Runnable showToast = () -> {
BaseFragment fragment = LaunchActivity.getSafeLastFragment();
if (fragment == null) return;
final BulletinFactory bf = BulletinFactory.of(fragment);
AndroidUtilities.runOnUIThread(() -> {
if (LaunchActivity.getSafeLastFragment() == null) return;
final BulletinFactory bf = bulletinFactory == null ? BulletinFactory.of(LaunchActivity.getSafeLastFragment()) : bulletinFactory;
if (bf == null) return;
bf
.createSimpleBulletin(
R.raw.msg_antispam,
LocaleController.getString(R.string.ReportChatSent),
LocaleController.getString(R.string.Reported2)
R.raw.msg_antispam,
LocaleController.getString(R.string.ReportChatSent),
LocaleController.getString(R.string.Reported2)
)
.setDuration(Bulletin.DURATION_PROLONG)
.show();
};
AndroidUtilities.runOnUIThread(showToast, 220);
}, 200);
}
}, 200);
}
});
sheet.setOnDismissListener(() -> {
if (!done[0] && whenDone != null) {
done[0] = true;
whenDone.run(false);
}
});
sheet.show();
} else if (response instanceof TLRPC.TL_reportResultReported || true) {
AndroidUtilities.runOnUIThread(() -> {
if (!done[0] && whenDone != null) {
done[0] = true;
whenDone.run(true);
}
Runnable showToast = () -> {
BaseFragment fragment = LaunchActivity.getSafeLastFragment();
if (fragment == null) return;
final BulletinFactory bf = BulletinFactory.of(fragment);
if (bf == null) return;
bf
.createSimpleBulletin(
R.raw.msg_antispam,
LocaleController.getString(R.string.ReportChatSent),
LocaleController.getString(R.string.Reported2)
)
.setDuration(Bulletin.DURATION_PROLONG)
.show();
};
AndroidUtilities.runOnUIThread(showToast, 220);
}, 200);
}
});
}

View file

@ -35,6 +35,7 @@ import org.telegram.messenger.Emoji;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.utils.tlutils.TLKeyboardHelper;
import org.telegram.messenger.utils.tlutils.TlUtils;
import org.telegram.tgnet.TLRPC;
import org.telegram.tgnet.tl.TL_keyboard;
import org.telegram.ui.ActionBar.Theme;
@ -127,6 +128,10 @@ public class BotKeyboardView extends LinearLayout implements InAppKeyboardInsetV
}
public void setButtons(TLRPC.TL_replyKeyboardMarkup buttons) {
if (TlUtils.tlEquals(buttons, botButtons)) {
return;
}
botButtons = buttons;
buttonViews.clear();

View file

@ -21,8 +21,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
defaultConfig.applicationId = APP_PACKAGE
@ -172,7 +172,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
targetSdkVersion 36
versionName APP_VERSION_NAME
ndkVersion "27.2.12479018"
@ -182,8 +182,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' // , '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}
}

View file

@ -34,8 +34,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
defaultConfig.applicationId = APP_PACKAGE
@ -168,7 +168,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
targetSdkVersion 36
versionName APP_VERSION_NAME
ndkVersion "27.2.12479018"
@ -178,8 +178,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' // , '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}
}

View file

@ -29,8 +29,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
defaultConfig.applicationId = APP_PACKAGE
@ -137,7 +137,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
targetSdkVersion 36
versionName APP_VERSION_NAME
ndkVersion "27.2.12479018"
@ -147,8 +147,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' //, '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}
}

View file

@ -23,8 +23,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
defaultConfig.applicationId = APP_PACKAGE
@ -128,7 +128,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
targetSdkVersion 36
versionName APP_VERSION_NAME
ndkVersion "27.2.12479018"
@ -138,8 +138,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' //, '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}
}

View file

@ -29,8 +29,8 @@ dependencies {
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
compileSdkVersion 36
buildToolsVersion '36.0.0'
defaultConfig.applicationId = APP_PACKAGE
@ -138,7 +138,7 @@ android {
defaultConfig {
minSdkVersion 26
targetSdkVersion 35
targetSdkVersion 36
versionName APP_VERSION_NAME
ndkVersion "27.2.12479018"
@ -148,8 +148,9 @@ android {
externalNativeBuild {
cmake {
version '3.10.2'
version '3.22.1'
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21' //, '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
targets 'tmessages.49'
}
}

View file

@ -6,13 +6,31 @@ buildscript {
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:8.6.1'
classpath 'com.android.tools.build:gradle:8.10.1'
classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.huawei.agconnect:agcp:1.9.1.301'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0"
}
}
repositories {
google()
}
// Strip JLatexMath fonts we don't ship (transitive AAR assets from
// io.noties.markwon:ext-latex -> ru.noties:jlatexmath-android, ~764 KB total under
// assets/org/scilab/forge/jlatexmath/fonts/). Has to live in the APK modules — a
// library's androidResources.ignoreAssetsPattern doesn't filter packaging in apps
// that consume it. Using subprojects keeps it in one place.
// keep: base/, latin/, maths/, euler/ (\mathbb, \mathcal, \mathfrak still work)
// drop: latin/optional/, maths/optional/ (~290 KB; \textbf/\textit/\mathds fall back)
// licences/ (~20 KB; pure license text files)
subprojects {
plugins.withId('com.android.application') {
android {
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~:!optional:!licences:!*stmary*:!*eufb*'
}
}
}
}

View file

@ -14,7 +14,7 @@ import org.gradle.api.tasks.TaskAction
import org.telegram.tlrpc.SchemeAllLayersParser
import org.telegram.tlrpc.SchemeCodeGen
import org.telegram.tlrpc.SchemeTlValidator
import org.telegram.tlrpc.models.RULES
import org.telegram.tlrpc.models.RulesHolder
import org.telegram.tlrpc.models.TlObjectWithLayer
import org.telegram.tlrpc.schema.TlSchemaJsonParser
import org.telegram.tlrpc.telegram.TelegramCodeParser
@ -64,7 +64,7 @@ abstract class GenerateSchemeTask : DefaultTask() {
val telegramClasses = TelegramCodeParser.parse(files)
val tlSchemaFull = TlSchemaJsonParser.parse(resourcesDir, LAYER)
val tlSchemaFilter = tlSchemaFull.applyRules(RULES.rules)
val tlSchemaFilter = tlSchemaFull.applyRules(RulesHolder.rules)
val undefinedTelegramClasses = telegramClasses.groupedByConstructorAll.filterKeys {
it !in tlSchemaFull.magicsAll
@ -77,7 +77,7 @@ abstract class GenerateSchemeTask : DefaultTask() {
val classesByUniqueIds = telegramClasses.groupedByConstructorUnique
val schema = SchemeAllLayersParser.parseAllLayers(resourcesDir)
val dep = RULES.rules.databaseTypes
val dep = RulesHolder.rules.databaseTypes
val legacyConstrKeys = schema.schemes.map { s ->
val types = dep
.mapNotNull { s.dependenciesTransitive[it] }
@ -181,7 +181,7 @@ abstract class GenerateSchemeTask : DefaultTask() {
) {
needSuper = false
}
if (!RULES.rules.filterConstructor(constructor.tl.key.name)) continue
if (!RulesHolder.rules.filterConstructor(constructor.tl.key.name)) continue
sealedClassBuilder.addType(
SchemeCodeGen.generateDataClass(
@ -230,7 +230,7 @@ abstract class GenerateSchemeTask : DefaultTask() {
var testIndex = 0;
for (constructor in constructorsSorted) {
if (!RULES.rules.filterConstructor(constructor.tl.key.name)) continue
if (!RulesHolder.rules.filterConstructor(constructor.tl.key.name)) continue
val isEncrypted = constructor in encrypted
val isLegacy = constructor.layerLast < LAYER

View file

@ -1,91 +1,5 @@
package org.telegram.tlrpc.models
object RULES {
val rules = Rules(
databaseTypes = setOf(
"Message", "StoryItem", "Theme",
"Chat", "User",
"UserFull", "ChatFull",
"StarsTransaction", "StarGift",
"SavedStarGift", "InputStorePaymentPurpose", //, "ChatTheme"
"ForumTopic", "EphemeralMessage"
),
ignoredTypes = setOf(
"True",
"Vector t",
"smsjobs.Status",
"smsjobs.EligibilityToJoin",
"SmsJob",
"InputMessage",
"BotBusinessConnection",
"BotCommandScope",
"CdnConfig",
"CdnPublicKey",
"InputBotInlineMessage",
"InputBotInlineResult",
"InputBusinessAwayMessage",
"InputBusinessGreetingMessage",
"RequestedPeer",
"SavedContact",
"messages.BotPreparedInlineMessage",
"bots.BotInfo",
"AutoSaveException",
"AutoSaveSettings",
"account.AutoSaveSettings",
"account.Takeout",
"InputClientProxy",
"InputStarsTransaction",
"InputStickerSetItem",
"bots.AccessSettings"
),
ignoredConstructors = mapOf(
"Update" to setOf(
"updateAutoSaveSettings",
"updateBotBusinessConnect",
"updateBotCallbackQuery",
"updateBotChatBoost",
"updateBotChatInviteRequester",
"updateBotDeleteBusinessMessage",
"updateBotEditBusinessMessage",
"updateBotInlineQuery",
"updateBotInlineSend",
"updateBotMessageReaction",
"updateBotMessageReactions",
"updateBotNewBusinessMessage",
"updateBotPrecheckoutQuery",
"updateBotShippingQuery",
"updateBotStopped",
"updateBotWebhookJSON",
"updateBotWebhookJSONQuery",
"updateBusinessBotCallbackQuery",
"updateChatParticipant",
"updateInlineBotCallbackQuery",
"updatePtsChanged",
"updateSmsJob",
"updateBotGuestChatQuery",
"updateBotStarsSubscription"
),
"MessageAction" to setOf(
"messageActionRequestedPeerSentMe",
"messageActionSecureValuesSentMe"
),
"InputFileLocation" to setOf(
"inputTakeoutFileLocation",
"inputPhotoLegacyFileLocation"
),
"InputPaymentCredentials" to setOf("inputPaymentCredentialsApplePay"),
"InputStickerSet" to setOf("inputStickerSetAnimatedEmojiAnimations"),
"InputWebFileLocation" to setOf("inputWebFileAudioAlbumThumbLocation"),
"InputInvoice" to setOf("inputInvoiceBusinessBotTransferStars"),
"InputBotInlineMessageID" to setOf("inputBotInlineMessageID64"),
"InputPasskeyCredential" to setOf("inputPasskeyCredentialFirebasePNV"),
"InputRichMessage" to setOf("inputRichMessageHTML", "inputRichMessageMarkdown"),
"SendMessageAction" to setOf("inputSendMessageRichMessageDraftAction")
)
)
}
data class Rules(
val databaseTypes: Set<String>,
val ignoredTypes: Set<String>,

View file

@ -0,0 +1,87 @@
package org.telegram.tlrpc.models
object RulesHolder {
val rules = Rules(
databaseTypes = setOf(
"Message", "StoryItem", "Theme",
"Chat", "User",
"UserFull", "ChatFull",
"StarsTransaction", "StarGift",
"SavedStarGift", "InputStorePaymentPurpose", //, "ChatTheme"
"ForumTopic", "EphemeralMessage"
),
ignoredTypes = setOf(
"True",
"Vector t",
"smsjobs.Status",
"smsjobs.EligibilityToJoin",
"SmsJob",
"InputMessage",
"BotBusinessConnection",
"BotCommandScope",
"CdnConfig",
"CdnPublicKey",
"InputBotInlineMessage",
"InputBotInlineResult",
"InputBusinessAwayMessage",
"InputBusinessGreetingMessage",
"RequestedPeer",
"SavedContact",
"messages.BotPreparedInlineMessage",
"bots.BotInfo",
"AutoSaveException",
"AutoSaveSettings",
"account.AutoSaveSettings",
"account.Takeout",
"InputClientProxy",
"InputStarsTransaction",
"InputStickerSetItem",
"bots.AccessSettings"
),
ignoredConstructors = mapOf(
"Update" to setOf(
"updateAutoSaveSettings",
"updateBotBusinessConnect",
"updateBotCallbackQuery",
"updateBotChatBoost",
"updateBotChatInviteRequester",
"updateBotDeleteBusinessMessage",
"updateBotEditBusinessMessage",
"updateBotInlineQuery",
"updateBotInlineSend",
"updateBotMessageReaction",
"updateBotMessageReactions",
"updateBotNewBusinessMessage",
"updateBotPrecheckoutQuery",
"updateBotShippingQuery",
"updateBotStopped",
"updateBotWebhookJSON",
"updateBotWebhookJSONQuery",
"updateBusinessBotCallbackQuery",
"updateChatParticipant",
"updateInlineBotCallbackQuery",
"updatePtsChanged",
"updateSmsJob",
"updateBotGuestChatQuery",
"updateBotStarsSubscription"
),
"MessageAction" to setOf(
"messageActionRequestedPeerSentMe",
"messageActionSecureValuesSentMe"
),
"InputFileLocation" to setOf(
"inputTakeoutFileLocation",
"inputPhotoLegacyFileLocation"
),
"InputPaymentCredentials" to setOf("inputPaymentCredentialsApplePay"),
"InputStickerSet" to setOf("inputStickerSetAnimatedEmojiAnimations"),
"InputWebFileLocation" to setOf("inputWebFileAudioAlbumThumbLocation"),
"InputInvoice" to setOf("inputInvoiceBusinessBotTransferStars"),
"InputBotInlineMessageID" to setOf("inputBotInlineMessageID64"),
"InputPasskeyCredential" to setOf("inputPasskeyCredentialFirebasePNV"),
"InputRichMessage" to setOf("inputRichMessageHTML", "inputRichMessageMarkdown"),
"SendMessageAction" to setOf("inputSendMessageRichMessageDraftAction")
)
)
}

View file

@ -13,14 +13,14 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Sat Mar 12 05:53:50 MSK 2016
APP_VERSION_CODE=7031
APP_VERSION_NAME=12.10.0
APP_VERSION_CODE=7038
APP_VERSION_NAME=12.10.1
APP_PACKAGE=org.telegram.messenger
IS_PRIVATE=false
RELEASE_KEY_PASSWORD=android
RELEASE_KEY_ALIAS=androidkey
RELEASE_STORE_PASSWORD=android
org.gradle.jvmargs=-Xmx4096M
org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=false