Update to 7.8.2 (2376)

Thanks to @alabiaga and @marcelpinto for help with improvements for Android 12.
https://github.com/DrKLO/Telegram/pull/1633
https://github.com/DrKLO/Telegram/pull/1636
https://github.com/DrKLO/Telegram/pull/1630
This commit is contained in:
DrKLO 2021-07-19 18:56:43 +03:00
parent 3ac3c37dd2
commit 7a60f948ae
83 changed files with 1038 additions and 877 deletions

View file

@ -1,11 +1,11 @@
FROM gradle:6.7.1-jdk8
FROM gradle:6.7.1-jdk11
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
ENV ANDROID_API_LEVEL android-30
ENV ANDROID_BUILD_TOOLS_VERSION 30.0.3
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/commandlinetools-linux-7302050_latest.zip
ENV ANDROID_API_LEVEL android-31
ENV ANDROID_BUILD_TOOLS_VERSION 31.0.0
ENV ANDROID_HOME /usr/local/android-sdk-linux
ENV ANDROID_NDK_VERSION 21.4.7075529
ENV ANDROID_VERSION 30
ENV ANDROID_VERSION 31
ENV ANDROID_NDK_HOME ${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/
ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
@ -15,12 +15,15 @@ RUN mkdir "$ANDROID_HOME" .android && \
unzip sdk.zip && \
rm sdk.zip
RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
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" \
"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/31.0.0/dx
RUN cp $ANDROID_HOME/build-tools/30.0.3/lib/dx.jar $ANDROID_HOME/build-tools/31.0.0/lib/dx.jar
ENV PATH ${ANDROID_NDK_HOME}:$PATH
ENV PATH ${ANDROID_NDK_HOME}/prebuilt/linux-x86_64/bin/:$PATH

View file

@ -42,8 +42,8 @@ dependencies {
}
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
compileSdkVersion 31
buildToolsVersion '31.0.0'
ndkVersion "21.4.7075529"
defaultConfig.applicationId = "org.telegram.messenger"
@ -299,7 +299,7 @@ android {
}
}
defaultConfig.versionCode = 2372
defaultConfig.versionCode = 2376
applicationVariants.all { variant ->
variant.outputs.all { output ->
@ -318,7 +318,7 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
versionName "7.8.1"
versionName "7.8.2"
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']

View file

@ -482,7 +482,7 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
uint32_t paddedDataSize = 192;
uint32_t encryptedDataSize = keySize + paddedDataSize + SHA256_DIGEST_LENGTH;
uint32_t additionalSize = innerDataSize < paddedDataSize ? paddedDataSize - innerDataSize : 0;
NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH);
NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH + 256);
innerDataBuffer->position(encryptedDataSize);
innerData->serializeToStream(innerDataBuffer);
@ -518,12 +518,13 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
}
bool ok = false;
size_t resLen = BN_bn2bin(rsaKey->n, innerDataBuffer->bytes() + encryptedDataSize);
uint32_t offset = encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH;
size_t resLen = BN_bn2bin(rsaKey->n, innerDataBuffer->bytes() + offset);
const auto shift = (256 - resLen);
for (auto i = 0; i != 256; ++i) {
const auto a = innerDataBuffer->bytes()[i];
const auto b = (i < shift) ? 0 : innerDataBuffer->bytes()[encryptedDataSize + i - shift];
const auto b = (i < shift) ? 0 : innerDataBuffer->bytes()[offset + i - shift];
if (a > b) {
break;
} else if (a < b) {
@ -544,9 +545,9 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
BN_mod_exp(r, a, rsaKey->e, rsaKey->n, bnContext);
uint32_t size = BN_num_bytes(r);
auto rsaEncryptedData = new ByteArray(size >= 256 ? size : 256);
size_t resLen = BN_bn2bin(r, rsaEncryptedData->bytes);
if (256 - resLen > 0) {
memset(rsaEncryptedData->bytes + resLen, 0, 256 - resLen);
BN_bn2bin(r, rsaEncryptedData->bytes + (size < 256 ? (256 - size) : 0));
if (256 - size > 0) {
memset(rsaEncryptedData->bytes, 0, 256 - size);
}
BN_free(a);
BN_free(r);

View file

@ -911,6 +911,8 @@ add_library(tgcalls STATIC
voip/tgcalls/VideoCaptureInterface.cpp
voip/tgcalls/VideoCaptureInterfaceImpl.cpp
voip/tgcalls/AudioDeviceHelper.cpp
voip/tgcalls/SctpDataChannelProviderInterfaceImpl.cpp
voip/tgcalls/TurnCustomizerImpl.cpp
voip/tgcalls/reference/InstanceImplReference.cpp
voip/tgcalls/legacy/InstanceImplLegacy.cpp
voip/tgcalls/group/GroupNetworkManager.cpp

View file

@ -45,7 +45,7 @@ int FormatPriority(const VideoFormat &format, const std::vector<std::string> &pr
}
return result;
}();
for (int i = 0; i < preferredCodecs.size(); i++) {
for (const auto &name : kSupported) {
if (absl::EqualsIgnoreCase(format.name, preferredCodecs[i]) && absl::EqualsIgnoreCase(format.name, name)) {
@ -114,12 +114,6 @@ std::vector<VideoFormat>::const_iterator FindEqualFormat(
});
}
bool ContainsEqualFormat(
const std::vector<VideoFormat> &list,
const VideoFormat &format) {
return FindEqualFormat(list, format) != list.end();
}
void AddDefaultFeedbackParams(cricket::VideoCodec *codec) {
// Don't add any feedback params for RED and ULPFEC.
if (codec->name == cricket::kRedCodecName || codec->name == cricket::kUlpfecCodecName)

View file

@ -285,7 +285,6 @@ void EncryptedConnection::appendAdditionalMessages(rtc::CopyOnWriteBuffer &buffe
}
const auto now = rtc::TimeMillis();
auto someWereNotAdded = false;
for (auto &resending : _myNotYetAckedMessages) {
const auto sent = resending.lastSent;
const auto when = sent
@ -471,6 +470,7 @@ auto EncryptedConnection::processPacket(
}
const auto success = reader.ReadUInt32(&currentSeq);
assert(success);
(void)success;
currentCounter = CounterFromSeq(currentSeq);
additionalMessage = true;

View file

@ -72,6 +72,7 @@ void Serialize(rtc::ByteBufferWriter &to, const cricket::Candidate &from) {
std::string serialized;
const auto success = iceCandidate.ToString(&serialized);
assert(success);
(void)success;
Serialize(to, serialized);
}

View file

@ -12,6 +12,7 @@
#include "api/jsep_ice_candidate.h"
#include "rtc_base/network_monitor_factory.h"
#include "TurnCustomizerImpl.h"
#include "platform/PlatformInterface.h"
extern "C" {
@ -61,24 +62,6 @@ private:
std::string _value;
};
class TurnCustomizerImpl : public webrtc::TurnCustomizer {
public:
TurnCustomizerImpl() {
}
virtual ~TurnCustomizerImpl() {
}
void MaybeModifyOutgoingStunMessage(cricket::PortInterface* port,
cricket::StunMessage* message) override {
message->AddAttribute(std::make_unique<cricket::StunByteStringAttribute>(cricket::STUN_ATTR_SOFTWARE, "Telegram "));
}
bool AllowChannelData(cricket::PortInterface* port, const void *data, size_t size, bool payload) override {
return true;
}
};
NetworkManager::NetworkManager(
rtc::Thread *thread,
EncryptionKey encryptionKey,

View file

@ -0,0 +1,158 @@
#include "SctpDataChannelProviderInterfaceImpl.h"
#include "p2p/base/dtls_transport.h"
namespace tgcalls {
SctpDataChannelProviderInterfaceImpl::SctpDataChannelProviderInterfaceImpl(
cricket::DtlsTransport *transportChannel,
bool isOutgoing,
std::function<void(bool)> onStateChanged,
std::function<void()> onTerminated,
std::function<void(std::string const &)> onMessageReceived,
std::shared_ptr<Threads> threads
) :
_threads(std::move(threads)),
_onStateChanged(onStateChanged),
_onTerminated(onTerminated),
_onMessageReceived(onMessageReceived) {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransportFactory.reset(new cricket::SctpTransportFactory(_threads->getNetworkThread()));
_sctpTransport = _sctpTransportFactory->CreateSctpTransport(transportChannel);
_sctpTransport->SignalReadyToSendData.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpReadyToSendData);
_sctpTransport->SignalDataReceived.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpDataReceived);
_sctpTransport->SignalClosedAbruptly.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpClosedAbruptly);
webrtc::InternalDataChannelInit dataChannelInit;
dataChannelInit.id = 0;
dataChannelInit.open_handshake_role = isOutgoing ? webrtc::InternalDataChannelInit::kOpener : webrtc::InternalDataChannelInit::kAcker;
_dataChannel = webrtc::SctpDataChannel::Create(
this,
"data",
dataChannelInit,
_threads->getNetworkThread(),
_threads->getNetworkThread()
);
_dataChannel->RegisterObserver(this);
}
SctpDataChannelProviderInterfaceImpl::~SctpDataChannelProviderInterfaceImpl() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->UnregisterObserver();
_dataChannel->Close();
_dataChannel = nullptr;
_sctpTransport = nullptr;
_sctpTransportFactory.reset();
}
void SctpDataChannelProviderInterfaceImpl::sendDataChannelMessage(std::string const &message) {
assert(_threads->getNetworkThread()->IsCurrent());
if (_isDataChannelOpen) {
RTC_LOG(LS_INFO) << "Outgoing DataChannel message: " << message;
webrtc::DataBuffer buffer(message);
_dataChannel->Send(buffer);
} else {
RTC_LOG(LS_INFO) << "Could not send an outgoing DataChannel message: the channel is not open";
}
}
void SctpDataChannelProviderInterfaceImpl::OnStateChange() {
assert(_threads->getNetworkThread()->IsCurrent());
auto state = _dataChannel->state();
bool isDataChannelOpen = state == webrtc::DataChannelInterface::DataState::kOpen;
if (_isDataChannelOpen != isDataChannelOpen) {
_isDataChannelOpen = isDataChannelOpen;
_onStateChanged(_isDataChannelOpen);
}
}
void SctpDataChannelProviderInterfaceImpl::OnMessage(const webrtc::DataBuffer& buffer) {
assert(_threads->getNetworkThread()->IsCurrent());
if (!buffer.binary) {
std::string messageText(buffer.data.data(), buffer.data.data() + buffer.data.size());
RTC_LOG(LS_INFO) << "Incoming DataChannel message: " << messageText;
_onMessageReceived(messageText);
}
}
void SctpDataChannelProviderInterfaceImpl::updateIsConnected(bool isConnected) {
assert(_threads->getNetworkThread()->IsCurrent());
if (isConnected) {
if (!_isSctpTransportStarted) {
_isSctpTransportStarted = true;
_sctpTransport->Start(5000, 5000, 262144);
}
}
}
void SctpDataChannelProviderInterfaceImpl::sctpReadyToSendData() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnTransportReady(true);
}
void SctpDataChannelProviderInterfaceImpl::sctpClosedAbruptly() {
assert(_threads->getNetworkThread()->IsCurrent());
if (_onTerminated) {
_onTerminated();
}
}
void SctpDataChannelProviderInterfaceImpl::sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer) {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnDataReceived(params, buffer);
}
bool SctpDataChannelProviderInterfaceImpl::SendData(int sid, const webrtc::SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, cricket::SendDataResult* result) {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->SendData(sid, params, payload);
}
bool SctpDataChannelProviderInterfaceImpl::ConnectDataChannel(webrtc::SctpDataChannel *data_channel) {
assert(_threads->getNetworkThread()->IsCurrent());
return true;
}
void SctpDataChannelProviderInterfaceImpl::DisconnectDataChannel(webrtc::SctpDataChannel* data_channel) {
assert(_threads->getNetworkThread()->IsCurrent());
return;
}
void SctpDataChannelProviderInterfaceImpl::AddSctpDataStream(int sid) {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransport->OpenStream(sid);
}
void SctpDataChannelProviderInterfaceImpl::RemoveSctpDataStream(int sid) {
assert(_threads->getNetworkThread()->IsCurrent());
_threads->getNetworkThread()->Invoke<void>(RTC_FROM_HERE, [this, sid]() {
_sctpTransport->ResetStream(sid);
});
}
bool SctpDataChannelProviderInterfaceImpl::ReadyToSendData() const {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->ReadyToSendData();
}
}

View file

@ -0,0 +1,64 @@
#ifndef TGCALLS_SCTP_DATA_CHANNEL_PROVIDER_IMPL_H
#define TGCALLS_SCTP_DATA_CHANNEL_PROVIDER_IMPL_H
#include "media/sctp/sctp_transport_factory.h"
#include "api/turn_customizer.h"
#include "api/data_channel_interface.h"
#include "pc/sctp_data_channel.h"
#include "pc/sctp_transport.h"
#include "StaticThreads.h"
namespace cricket {
class DtlsTransport;
} // namespace cricket
namespace tgcalls {
class SctpDataChannelProviderInterfaceImpl : public sigslot::has_slots<>, public webrtc::SctpDataChannelProviderInterface, public webrtc::DataChannelObserver {
public:
SctpDataChannelProviderInterfaceImpl(
cricket::DtlsTransport *transportChannel,
bool isOutgoing,
std::function<void(bool)> onStateChanged,
std::function<void()> onTerminated,
std::function<void(std::string const &)> onMessageReceived,
std::shared_ptr<Threads> threads
);
virtual ~SctpDataChannelProviderInterfaceImpl();
void updateIsConnected(bool isConnected);
void sendDataChannelMessage(std::string const &message);
virtual void OnStateChange() override;
virtual void OnMessage(const webrtc::DataBuffer& buffer) override;
virtual bool SendData(int sid, const webrtc::SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, cricket::SendDataResult* result = nullptr) override;
virtual bool ConnectDataChannel(webrtc::SctpDataChannel *data_channel) override;
virtual void DisconnectDataChannel(webrtc::SctpDataChannel* data_channel) override;
virtual void AddSctpDataStream(int sid) override;
virtual void RemoveSctpDataStream(int sid) override;
virtual bool ReadyToSendData() const override;
private:
void sctpReadyToSendData();
void sctpClosedAbruptly();
void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer);
private:
std::shared_ptr<Threads> _threads;
std::function<void(bool)> _onStateChanged;
std::function<void()> _onTerminated;
std::function<void(std::string const &)> _onMessageReceived;
std::unique_ptr<cricket::SctpTransportFactory> _sctpTransportFactory;
std::unique_ptr<cricket::SctpTransportInternal> _sctpTransport;
rtc::scoped_refptr<webrtc::SctpDataChannel> _dataChannel;
bool _isSctpTransportStarted = false;
bool _isDataChannelOpen = false;
};
} // namespace tgcalls
#endif

View file

@ -64,7 +64,6 @@ public:
network_->DisallowAllInvokes();
media_ = create("tgc-media" + suffix);
worker_ = create("tgc-work" + suffix);
process_ = create("tgc-process" + suffix);
worker_->DisallowAllInvokes();
worker_->AllowInvokesToThread(network_.get());
}
@ -78,9 +77,6 @@ public:
rtc::Thread *getWorkerThread() override {
return worker_.get();
}
rtc::Thread *getProcessThread() override {
return process_.get();
}
rtc::scoped_refptr<webrtc::SharedModuleThread> getSharedModuleThread() override {
// This function must be called from a single thread because of SharedModuleThread implementation
// So we don't care about making it thread safe
@ -96,7 +92,6 @@ private:
Thread network_;
Thread media_;
Thread worker_;
Thread process_;
rtc::scoped_refptr<webrtc::SharedModuleThread> shared_module_thread_;
static Thread create(const std::string &name) {
@ -146,10 +141,6 @@ rtc::Thread *getWorkerThread() {
return getThreads()->getWorkerThread();
}
rtc::Thread *getProcessThread() {
return getThreads()->getProcessThread();
}
std::shared_ptr<Threads> &getThreads() {
static std::shared_ptr<Threads> threads = std::make_shared<ThreadsImpl>(0);
return threads;

View file

@ -20,7 +20,6 @@ public:
virtual rtc::Thread *getNetworkThread() = 0;
virtual rtc::Thread *getMediaThread() = 0;
virtual rtc::Thread *getWorkerThread() = 0;
virtual rtc::Thread *getProcessThread() = 0;
virtual rtc::scoped_refptr<webrtc::SharedModuleThread> getSharedModuleThread() = 0;
// it is not possible to decrease pool size
@ -32,7 +31,6 @@ namespace StaticThreads {
rtc::Thread *getNetworkThread();
rtc::Thread *getMediaThread();
rtc::Thread *getWorkerThread();
rtc::Thread *getProcessThread();
rtc::scoped_refptr<webrtc::SharedModuleThread> getSharedMoudleThread();
std::shared_ptr<Threads> &getThreads();
}

View file

@ -0,0 +1,21 @@
#include "TurnCustomizerImpl.h"
#include "api/transport/stun.h"
namespace tgcalls {
TurnCustomizerImpl::TurnCustomizerImpl() {
}
TurnCustomizerImpl::~TurnCustomizerImpl() {
}
void TurnCustomizerImpl::MaybeModifyOutgoingStunMessage(cricket::PortInterface* port, cricket::StunMessage* message) {
message->AddAttribute(std::make_unique<cricket::StunByteStringAttribute>(cricket::STUN_ATTR_SOFTWARE, "Telegram "));
}
bool TurnCustomizerImpl::AllowChannelData(cricket::PortInterface* port, const void *data, size_t size, bool payload) {
return true;
}
}

View file

@ -0,0 +1,19 @@
#ifndef TGCALLS_TURN_CUSTOMIZER_H
#define TGCALLS_TURN_CUSTOMIZER_H
#include "api/turn_customizer.h"
namespace tgcalls {
class TurnCustomizerImpl : public webrtc::TurnCustomizer {
public:
TurnCustomizerImpl();
virtual ~TurnCustomizerImpl();
void MaybeModifyOutgoingStunMessage(cricket::PortInterface* port, cricket::StunMessage* message) override;
bool AllowChannelData(cricket::PortInterface* port, const void *data, size_t size, bool payload) override;
};
} // namespace tgcalls
#endif

View file

@ -520,11 +520,14 @@ class AudioSinkImpl: public webrtc::AudioSinkInterface {
public:
struct Update {
float level = 0.0f;
std::shared_ptr<webrtc::AudioBuffer> buffer;
std::shared_ptr<CombinedVad> vad;
bool hasSpeech = false;
Update(float level_, webrtc::AudioBuffer *buffer_, std::shared_ptr<CombinedVad> vad_) :
level(level_), buffer(std::shared_ptr<webrtc::AudioBuffer>(buffer_)), vad(vad_) {
Update(float level_, bool hasSpech_) :
level(level_), hasSpeech(hasSpech_) {
}
Update(const Update &other) :
level(other.level), hasSpeech(other.hasSpeech) {
}
};
@ -550,7 +553,7 @@ public:
frame.ntp_time_ms = 0;
_onAudioFrame(_channel_id.actualSsrc, frame);
}
if (_update && audio.channels == 1) {
if (_update && audio.channels == 1) {
const int16_t *samples = (const int16_t *)audio.data;
int numberOfSamplesInFrame = (int)audio.samples_per_channel;
@ -573,17 +576,7 @@ public:
float level = ((float)(_peak)) / 8000.0f;
_peak = 0;
_peakCount = 0;
webrtc::AudioBuffer *buffer;
if (_vad->incWaitingFrames()) {
buffer = new webrtc::AudioBuffer(audio.sample_rate, 1, 48000, 1, 48000, 1);
webrtc::StreamConfig config(audio.sample_rate, 1);
buffer->CopyFrom(samples, config);
} else {
buffer = nullptr;
}
_update(Update(level, buffer, _vad));
_update(Update(level, level >= 1.0f));
}
}
}
@ -2929,12 +2922,6 @@ public:
}
void setIsMuted(bool isMuted) {
if (_videoContentType == VideoContentType::Screencast) {
if (isMuted) {
return;
}
}
if (_isMuted == isMuted) {
return;
}
@ -3011,23 +2998,23 @@ public:
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
std::function<void(AudioSinkImpl::Update)> onAudioSinkUpdate;
/*if (_audioLevelsUpdated) {
onAudioSinkUpdate = [weak, ssrc = ssrc, threads = _threads](AudioSinkImpl::Update update) {
threads->getProcessThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update, threads]() {
bool voice = update.vad->update(update.buffer.get());
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update, voice]() {
auto strong = weak.lock();
if (!strong) {
return;
}
GroupLevelValue mappedUpdate;
mappedUpdate.level = update.level;
mappedUpdate.voice = voice;
strong->_audioLevels[ssrc] = mappedUpdate;
});
});
};
}*/
if (ssrc.actualSsrc != ssrc.networkSsrc) {
if (_audioLevelsUpdated) {
onAudioSinkUpdate = [weak, ssrc = ssrc, threads = _threads](AudioSinkImpl::Update update) {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update]() {
auto strong = weak.lock();
if (!strong) {
return;
}
InternalGroupLevelValue updated;
updated.value.level = update.level;
updated.value.voice = update.hasSpeech;
updated.timestamp = rtc::TimeMillis();
strong->_audioLevels.insert(std::make_pair(ChannelId(ssrc), std::move(updated)));
});
};
}
}
std::unique_ptr<IncomingAudioChannel> channel(new IncomingAudioChannel(
_channelManager.get(),

View file

@ -17,194 +17,12 @@
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "platform/PlatformInterface.h"
#include "TurnCustomizerImpl.h"
#include "SctpDataChannelProviderInterfaceImpl.h"
#include "StaticThreads.h"
namespace tgcalls {
class TurnCustomizerImpl : public webrtc::TurnCustomizer {
public:
TurnCustomizerImpl() {
}
virtual ~TurnCustomizerImpl() {
}
void MaybeModifyOutgoingStunMessage(cricket::PortInterface* port,
cricket::StunMessage* message) override {
message->AddAttribute(std::make_unique<cricket::StunByteStringAttribute>(cricket::STUN_ATTR_SOFTWARE, "Telegram "));
}
bool AllowChannelData(cricket::PortInterface* port, const void *data, size_t size, bool payload) override {
return true;
}
};
class SctpDataChannelProviderInterfaceImpl : public sigslot::has_slots<>, public webrtc::SctpDataChannelProviderInterface, public webrtc::DataChannelObserver {
public:
SctpDataChannelProviderInterfaceImpl(
cricket::DtlsTransport *transportChannel,
std::function<void(bool)> onStateChanged,
std::function<void()> onTerminated,
std::function<void(std::string const &)> onMessageReceived,
std::shared_ptr<Threads> threads
) :
_threads(std::move(threads)),
_onStateChanged(onStateChanged),
_onTerminated(onTerminated),
_onMessageReceived(onMessageReceived) {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransportFactory.reset(new cricket::SctpTransportFactory(_threads->getNetworkThread()));
_sctpTransport = _sctpTransportFactory->CreateSctpTransport(transportChannel);
_sctpTransport->SignalReadyToSendData.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpReadyToSendData);
_sctpTransport->SignalDataReceived.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpDataReceived);
_sctpTransport->SignalClosedAbruptly.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpClosedAbruptly);
webrtc::InternalDataChannelInit dataChannelInit;
dataChannelInit.id = 0;
_dataChannel = webrtc::SctpDataChannel::Create(
this,
"data",
dataChannelInit,
_threads->getNetworkThread(),
_threads->getNetworkThread()
);
_dataChannel->RegisterObserver(this);
}
virtual ~SctpDataChannelProviderInterfaceImpl() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->UnregisterObserver();
_dataChannel->Close();
_dataChannel = nullptr;
_sctpTransport = nullptr;
_sctpTransportFactory.reset();
}
void sendDataChannelMessage(std::string const &message) {
assert(_threads->getNetworkThread()->IsCurrent());
if (_isDataChannelOpen) {
RTC_LOG(LS_INFO) << "Outgoing DataChannel message: " << message;
webrtc::DataBuffer buffer(message);
_dataChannel->Send(buffer);
} else {
RTC_LOG(LS_INFO) << "Could not send an outgoing DataChannel message: the channel is not open";
}
}
virtual void OnStateChange() override {
assert(_threads->getNetworkThread()->IsCurrent());
auto state = _dataChannel->state();
bool isDataChannelOpen = state == webrtc::DataChannelInterface::DataState::kOpen;
if (_isDataChannelOpen != isDataChannelOpen) {
_isDataChannelOpen = isDataChannelOpen;
_onStateChanged(_isDataChannelOpen);
}
}
virtual void OnMessage(const webrtc::DataBuffer& buffer) override {
assert(_threads->getNetworkThread()->IsCurrent());
if (!buffer.binary) {
std::string messageText(buffer.data.data(), buffer.data.data() + buffer.data.size());
RTC_LOG(LS_INFO) << "Incoming DataChannel message: " << messageText;
_onMessageReceived(messageText);
}
}
void updateIsConnected(bool isConnected) {
assert(_threads->getNetworkThread()->IsCurrent());
if (isConnected) {
if (!_isSctpTransportStarted) {
_isSctpTransportStarted = true;
_sctpTransport->Start(5000, 5000, 262144);
}
}
}
void sctpReadyToSendData() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnTransportReady(true);
}
void sctpClosedAbruptly() {
assert(_threads->getNetworkThread()->IsCurrent());
if (_onTerminated) {
_onTerminated();
}
}
void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer) {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnDataReceived(params, buffer);
}
virtual bool SendData(int sid, const webrtc::SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, cricket::SendDataResult* result) override {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->SendData(sid, params, payload);
}
virtual bool ConnectDataChannel(webrtc::SctpDataChannel *data_channel) override {
assert(_threads->getNetworkThread()->IsCurrent());
return true;
}
virtual void DisconnectDataChannel(webrtc::SctpDataChannel* data_channel) override {
assert(_threads->getNetworkThread()->IsCurrent());
return;
}
virtual void AddSctpDataStream(int sid) override {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransport->OpenStream(sid);
}
virtual void RemoveSctpDataStream(int sid) override {
assert(_threads->getNetworkThread()->IsCurrent());
_threads->getNetworkThread()->Invoke<void>(RTC_FROM_HERE, [this, sid]() {
_sctpTransport->ResetStream(sid);
});
}
virtual bool ReadyToSendData() const override {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->ReadyToSendData();
}
private:
std::shared_ptr<Threads> _threads;
std::function<void(bool)> _onStateChanged;
std::function<void()> _onTerminated;
std::function<void(std::string const &)> _onMessageReceived;
std::unique_ptr<cricket::SctpTransportFactory> _sctpTransportFactory;
std::unique_ptr<cricket::SctpTransportInternal> _sctpTransport;
rtc::scoped_refptr<webrtc::SctpDataChannel> _dataChannel;
bool _isSctpTransportStarted = false;
bool _isDataChannelOpen = false;
};
enum {
kRtcpExpectedVersion = 2,
kRtcpMinHeaderLength = 4,
@ -589,6 +407,7 @@ void GroupNetworkManager::restartDataChannel() {
const auto weak = std::weak_ptr<GroupNetworkManager>(shared_from_this());
_dataChannelInterface.reset(new SctpDataChannelProviderInterfaceImpl(
_dtlsTransport.get(),
true,
[weak, threads = _threads](bool state) {
assert(threads->getNetworkThread()->IsCurrent());
const auto strong = weak.lock();

View file

@ -13,184 +13,12 @@
#include "p2p/base/dtls_transport_factory.h"
#include "pc/dtls_srtp_transport.h"
#include "pc/dtls_transport.h"
#include "TurnCustomizerImpl.h"
#include "SctpDataChannelProviderInterfaceImpl.h"
#include "StaticThreads.h"
namespace tgcalls {
class TurnCustomizerImpl : public webrtc::TurnCustomizer {
public:
TurnCustomizerImpl() {
}
virtual ~TurnCustomizerImpl() {
}
void MaybeModifyOutgoingStunMessage(cricket::PortInterface* port,
cricket::StunMessage* message) override {
message->AddAttribute(std::make_unique<cricket::StunByteStringAttribute>(cricket::STUN_ATTR_SOFTWARE, "Telegram "));
}
bool AllowChannelData(cricket::PortInterface* port, const void *data, size_t size, bool payload) override {
return true;
}
};
class SctpDataChannelProviderInterfaceImpl : public sigslot::has_slots<>, public webrtc::SctpDataChannelProviderInterface, public webrtc::DataChannelObserver {
public:
SctpDataChannelProviderInterfaceImpl(
cricket::DtlsTransport *transportChannel,
bool isOutgoing,
std::function<void(bool)> onStateChanged,
std::function<void(std::string const &)> onMessageReceived,
std::shared_ptr<Threads> threads
) :
_threads(std::move(threads)),
_onStateChanged(onStateChanged),
_onMessageReceived(onMessageReceived) {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransportFactory.reset(new cricket::SctpTransportFactory(_threads->getNetworkThread()));
_sctpTransport = _sctpTransportFactory->CreateSctpTransport(transportChannel);
_sctpTransport->SignalReadyToSendData.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpReadyToSendData);
_sctpTransport->SignalDataReceived.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpDataReceived);
webrtc::InternalDataChannelInit dataChannelInit;
dataChannelInit.id = 0;
dataChannelInit.open_handshake_role = isOutgoing ? webrtc::InternalDataChannelInit::kOpener : webrtc::InternalDataChannelInit::kAcker;
_dataChannel = webrtc::SctpDataChannel::Create(
this,
"data",
dataChannelInit,
_threads->getNetworkThread(),
_threads->getNetworkThread()
);
_dataChannel->RegisterObserver(this);
}
virtual ~SctpDataChannelProviderInterfaceImpl() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->UnregisterObserver();
_dataChannel->Close();
_dataChannel = nullptr;
_sctpTransport = nullptr;
_sctpTransportFactory.reset();
}
void sendDataChannelMessage(std::string const &message) {
assert(_threads->getNetworkThread()->IsCurrent());
if (_isDataChannelOpen) {
RTC_LOG(LS_INFO) << "Outgoing DataChannel message: " << message;
webrtc::DataBuffer buffer(message);
_dataChannel->Send(buffer);
} else {
RTC_LOG(LS_INFO) << "Could not send an outgoing DataChannel message: the channel is not open";
}
}
virtual void OnStateChange() override {
assert(_threads->getNetworkThread()->IsCurrent());
auto state = _dataChannel->state();
bool isDataChannelOpen = state == webrtc::DataChannelInterface::DataState::kOpen;
if (_isDataChannelOpen != isDataChannelOpen) {
_isDataChannelOpen = isDataChannelOpen;
_onStateChanged(_isDataChannelOpen);
}
}
virtual void OnMessage(const webrtc::DataBuffer& buffer) override {
assert(_threads->getNetworkThread()->IsCurrent());
if (!buffer.binary) {
std::string messageText(buffer.data.data(), buffer.data.data() + buffer.data.size());
RTC_LOG(LS_INFO) << "Incoming DataChannel message: " << messageText;
_onMessageReceived(messageText);
}
}
void updateIsConnected(bool isConnected) {
assert(_threads->getNetworkThread()->IsCurrent());
if (isConnected) {
if (!_isSctpTransportStarted) {
_isSctpTransportStarted = true;
_sctpTransport->Start(5000, 5000, 262144);
}
}
}
void sctpReadyToSendData() {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnTransportReady(true);
}
void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer) {
assert(_threads->getNetworkThread()->IsCurrent());
_dataChannel->OnDataReceived(params, buffer);
}
virtual bool SendData(const cricket::SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, cricket::SendDataResult* result) override {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->SendData(params, payload);
}
virtual bool ConnectDataChannel(webrtc::SctpDataChannel *data_channel) override {
assert(_threads->getNetworkThread()->IsCurrent());
return true;
}
virtual void DisconnectDataChannel(webrtc::SctpDataChannel* data_channel) override {
assert(_threads->getNetworkThread()->IsCurrent());
return;
}
virtual void AddSctpDataStream(int sid) override {
assert(_threads->getNetworkThread()->IsCurrent());
_sctpTransport->OpenStream(sid);
}
virtual void RemoveSctpDataStream(int sid) override {
assert(_threads->getNetworkThread()->IsCurrent());
_threads->getNetworkThread()->Invoke<void>(RTC_FROM_HERE, [this, sid]() {
_sctpTransport->ResetStream(sid);
});
}
virtual bool ReadyToSendData() const override {
assert(_threads->getNetworkThread()->IsCurrent());
return _sctpTransport->ReadyToSendData();
}
private:
std::shared_ptr<Threads> _threads;
std::function<void(bool)> _onStateChanged;
std::function<void(std::string const &)> _onMessageReceived;
std::unique_ptr<cricket::SctpTransportFactory> _sctpTransportFactory;
std::unique_ptr<cricket::SctpTransportInternal> _sctpTransport;
rtc::scoped_refptr<webrtc::SctpDataChannel> _dataChannel;
bool _isSctpTransportStarted = false;
bool _isDataChannelOpen = false;
};
webrtc::CryptoOptions NativeNetworkingImpl::getDefaulCryptoOptions() {
auto options = webrtc::CryptoOptions();
options.srtp.enable_aes128_sha1_80_crypto_cipher = true;
@ -355,6 +183,14 @@ void NativeNetworkingImpl::start() {
}
strong->_dataChannelStateUpdated(state);
},
[weak, threads = _threads]() {
assert(threads->getNetworkThread()->IsCurrent());
const auto strong = weak.lock();
if (!strong) {
return;
}
//strong->restartDataChannel();
},
[weak, threads = _threads](std::string const &message) {
assert(threads->getNetworkThread()->IsCurrent());
const auto strong = weak.lock();

View file

@ -423,7 +423,7 @@
android:name=".voip.CallNotificationSoundProvider"
android:exported="true"/>
<receiver android:name=".ChatsWidgetProvider">
<receiver android:name=".ChatsWidgetProvider" android:exported="false">
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/chats_widget_info" />
<intent-filter>
@ -435,7 +435,7 @@
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false" />
<receiver android:name=".ContactsWidgetProvider">
<receiver android:name=".ContactsWidgetProvider" android:exported="false">
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/contacts_widget_info" />
<intent-filter>

View file

@ -1747,6 +1747,9 @@ public class AndroidUtilities {
}
public static void runOnUIThread(Runnable runnable, long delay) {
if (ApplicationLoader.applicationHandler == null) {
return;
}
if (delay == 0) {
ApplicationLoader.applicationHandler.post(runnable);
} else {
@ -1755,6 +1758,9 @@ public class AndroidUtilities {
}
public static void cancelRunOnUIThread(Runnable runnable) {
if (ApplicationLoader.applicationHandler == null) {
return;
}
ApplicationLoader.applicationHandler.removeCallbacks(runnable);
}

View file

@ -15,12 +15,12 @@ public class BuildVars {
public static boolean DEBUG_VERSION = false;
public static boolean DEBUG_PRIVATE_VERSION = false;
public static boolean LOGS_ENABLED = true;
public static boolean LOGS_ENABLED = false;
public static boolean USE_CLOUD_STRINGS = true;
public static boolean CHECK_UPDATES = true;
public static boolean NO_SCOPED_STORAGE = true/* || Build.VERSION.SDK_INT <= 28*/;
public static int BUILD_VERSION = 2372;
public static String BUILD_VERSION_STRING = "7.8.0";
public static int BUILD_VERSION = 2376;
public static String BUILD_VERSION_STRING = "7.8.2";
public static int APP_ID = 4;
public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103";
public static String APPCENTER_HASH = "a5b5c4f5-51da-dedc-9918-d9766a22ca7c";

View file

@ -28,13 +28,13 @@ public class ChatsWidgetProvider extends AppWidgetProvider {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
updateWidget(context, appWidgetManager, appWidgetId, false);
updateWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
updateWidget(context, appWidgetManager, appWidgetId, true);
updateWidget(context, appWidgetManager, appWidgetId);
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
}
@ -65,7 +65,7 @@ public class ChatsWidgetProvider extends AppWidgetProvider {
return n - 1;
}
public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, boolean edit) {
public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
ApplicationLoader.postInitApplication();
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
@ -80,6 +80,11 @@ public class ChatsWidgetProvider extends AppWidgetProvider {
int id;
if (!deleted) {
int accountId = preferences.getInt("account" + appWidgetId, -1);
if (accountId == -1) {
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("account" + appWidgetId, UserConfig.selectedAccount);
editor.putInt("type" + appWidgetId, EditWidgetActivity.TYPE_CHATS).commit();
}
ArrayList<Long> selectedDialogs = new ArrayList<>();
if (accountId >= 0) {
AccountInstance.getInstance(accountId).getMessagesStorage().getWidgetDialogIds(appWidgetId, EditWidgetActivity.TYPE_CHATS, selectedDialogs, null, null, false);
@ -109,8 +114,6 @@ public class ChatsWidgetProvider extends AppWidgetProvider {
rv.setPendingIntentTemplate(R.id.list_view, contentIntent);
appWidgetManager.updateAppWidget(appWidgetId, rv);
if (edit) {
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_view);
}
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_view);
}
}

View file

@ -327,9 +327,11 @@ class ChatsRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
rv.setTextViewText(R.id.shortcut_widget_item_badge, String.format("%d", dialog.unread_count));
rv.setViewVisibility(R.id.shortcut_widget_item_badge, View.VISIBLE);
if (accountInstance.getMessagesController().isDialogMuted(dialog.id)) {
rv.setInt(R.id.shortcut_widget_item_badge, "setBackgroundResource", R.drawable.widget_counter_muted);
rv.setBoolean(R.id.shortcut_widget_item_badge, "setEnabled", false);
rv.setInt(R.id.shortcut_widget_item_badge, "setBackgroundResource", R.drawable.widget_badge_muted_background);
} else {
rv.setInt(R.id.shortcut_widget_item_badge, "setBackgroundResource", R.drawable.widget_counter);
rv.setBoolean(R.id.shortcut_widget_item_badge, "setEnabled", true);
rv.setInt(R.id.shortcut_widget_item_badge, "setBackgroundResource", R.drawable.widget_badge_background);
}
} else {
rv.setViewVisibility(R.id.shortcut_widget_item_badge, View.GONE);

View file

@ -28,7 +28,7 @@ public class ContactsWidgetProvider extends AppWidgetProvider {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
updateWidget(context, appWidgetManager, appWidgetId, false);
updateWidget(context, appWidgetManager, appWidgetId);
}
}
@ -53,7 +53,7 @@ public class ContactsWidgetProvider extends AppWidgetProvider {
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
updateWidget(context, appWidgetManager, appWidgetId, true);
updateWidget(context, appWidgetManager, appWidgetId);
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
}
@ -65,7 +65,7 @@ public class ContactsWidgetProvider extends AppWidgetProvider {
return n - 1;
}
public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, boolean edit) {
public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
ApplicationLoader.postInitApplication();
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
@ -80,6 +80,11 @@ public class ContactsWidgetProvider extends AppWidgetProvider {
int id;
if (!deleted) {
int accountId = preferences.getInt("account" + appWidgetId, -1);
if (accountId == -1) {
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("account" + appWidgetId, UserConfig.selectedAccount);
editor.putInt("type" + appWidgetId, EditWidgetActivity.TYPE_CHATS).commit();
}
ArrayList<Long> selectedDialogs = new ArrayList<>();
if (accountId >= 0) {
AccountInstance.getInstance(accountId).getMessagesStorage().getWidgetDialogIds(appWidgetId, EditWidgetActivity.TYPE_CONTACTS, selectedDialogs, null, null, false);
@ -111,8 +116,6 @@ public class ContactsWidgetProvider extends AppWidgetProvider {
rv.setPendingIntentTemplate(R.id.list_view, contentIntent);
appWidgetManager.updateAppWidget(appWidgetId, rv);
if (edit) {
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_view);
}
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_view);
}
}

View file

@ -899,7 +899,7 @@ public class MessageObject {
}
public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap<Integer, TLRPC.User> users, AbstractMap<Integer, TLRPC.Chat> chats, SparseArray<TLRPC.User> sUsers, SparseArray<TLRPC.Chat> sChats, boolean generateLayout, boolean checkMediaExists, long eid) {
Theme.createCommonChatResources(null);
Theme.createCommonChatResources();
currentAccount = accountNum;
messageOwner = message;
@ -2363,7 +2363,7 @@ public class MessageObject {
}
wantedBotKeyboardWidth = 0;
if (messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup || messageOwner.reactions != null && !messageOwner.reactions.results.isEmpty()) {
Theme.createCommonChatResources(null);
Theme.createCommonChatResources();
if (botButtonsLayout == null) {
botButtonsLayout = new StringBuilder();
} else {

View file

@ -2474,12 +2474,12 @@ public class MessagesController extends BaseController implements NotificationCe
}
if (chatsWidgets != null) {
for (int a = 0, N = chatsWidgets.size(); a < N; a++) {
ChatsWidgetProvider.updateWidget(ApplicationLoader.applicationContext, appWidgetManager, chatsWidgets.get(a), true);
ChatsWidgetProvider.updateWidget(ApplicationLoader.applicationContext, appWidgetManager, chatsWidgets.get(a));
}
}
if (contactsWidgets != null) {
for (int a = 0, N = contactsWidgets.size(); a < N; a++) {
ContactsWidgetProvider.updateWidget(ApplicationLoader.applicationContext, appWidgetManager, contactsWidgets.get(a), true);
ContactsWidgetProvider.updateWidget(ApplicationLoader.applicationContext, appWidgetManager, contactsWidgets.get(a));
}
}

View file

@ -47,6 +47,7 @@ import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.Person;
import androidx.core.app.RemoteInput;
import androidx.core.content.FileProvider;
import androidx.core.content.LocusIdCompat;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
@ -2749,11 +2750,22 @@ public class NotificationsController extends BaseController {
}
try {
String id = "ndid_" + did;
Intent shortcutIntent = new Intent(ApplicationLoader.applicationContext, OpenChatReceiver.class);
shortcutIntent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
if (did > 0) {
shortcutIntent.putExtra("userId", did);
} else {
shortcutIntent.putExtra("chatId", -did);
}
ShortcutInfoCompat.Builder shortcutBuilder = new ShortcutInfoCompat.Builder(ApplicationLoader.applicationContext, id)
.setShortLabel(chat != null ? name : UserObject.getFirstName(user))
.setLongLabel(name)
.setIntent(new Intent(Intent.ACTION_DEFAULT))
.setLongLived(true);
.setIntent(shortcutIntent)
.setLongLived(true)
.setLocusId(new LocusIdCompat(id));
Bitmap avatar = null;
if (person != null) {
@ -2763,11 +2775,9 @@ public class NotificationsController extends BaseController {
avatar = person.getIcon().getBitmap();
}
}
ArrayList<ShortcutInfoCompat> arrayList = new ArrayList<>(1);
arrayList.add(shortcutBuilder.build());
ShortcutManagerCompat.addDynamicShortcuts(ApplicationLoader.applicationContext, arrayList);
builder.setShortcutId(id);
NotificationCompat.BubbleMetadata.Builder bubbleBuilder = new NotificationCompat.BubbleMetadata.Builder();
ShortcutInfoCompat shortcut = shortcutBuilder.build();
ShortcutManagerCompat.pushDynamicShortcut(ApplicationLoader.applicationContext, shortcut);
builder.setShortcutInfo(shortcut);
Intent intent = new Intent(ApplicationLoader.applicationContext, BubbleActivity.class);
intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
if (did > 0) {
@ -2776,19 +2786,21 @@ public class NotificationsController extends BaseController {
intent.putExtra("chatId", -did);
}
intent.putExtra("currentAccount", currentAccount);
bubbleBuilder.setIntent(PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
IconCompat icon;
if (avatar != null) {
icon = IconCompat.createWithAdaptiveBitmap(avatar);
} else if (user != null) {
icon = IconCompat.createWithResource(ApplicationLoader.applicationContext, user.bot ? R.drawable.book_bot : R.drawable.book_user);
} else {
icon = IconCompat.createWithResource(ApplicationLoader.applicationContext, R.drawable.book_group);
}
NotificationCompat.BubbleMetadata.Builder bubbleBuilder =
new NotificationCompat.BubbleMetadata.Builder(
PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT),
icon);
bubbleBuilder.setSuppressNotification(opened_dialog_id == did);
bubbleBuilder.setAutoExpandBubble(false);
bubbleBuilder.setDesiredHeight(AndroidUtilities.dp(640));
if (avatar != null) {
bubbleBuilder.setIcon(IconCompat.createWithAdaptiveBitmap(avatar));
} else {
if (user != null) {
bubbleBuilder.setIcon(IconCompat.createWithResource(ApplicationLoader.applicationContext, user.bot ? R.drawable.book_bot : R.drawable.book_user));
} else {
bubbleBuilder.setIcon(IconCompat.createWithResource(ApplicationLoader.applicationContext, R.drawable.book_group));
}
}
builder.setBubbleMetadata(bubbleBuilder.build());
return id;
} catch (Exception e) {

View file

@ -284,15 +284,22 @@ public class SharedConfig {
}
if (pendingAppUpdate != null) {
long updateTime = 0;
int updateVerstion;
int updateVersion = 0;
String updateVersionString = null;
try {
PackageInfo packageInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
updateVerstion = packageInfo.versionCode;
updateVersion = packageInfo.versionCode;
updateVersionString = packageInfo.versionName;
} catch (Exception e) {
FileLog.e(e);
updateVerstion = BuildVars.BUILD_VERSION;
}
if (pendingAppUpdateBuildVersion != updateVerstion) {
if (updateVersion == 0) {
updateVersion = BuildVars.BUILD_VERSION;
}
if (updateVersionString == null) {
updateVersionString = BuildVars.BUILD_VERSION_STRING;
}
if (pendingAppUpdateBuildVersion != updateVersion || pendingAppUpdate.version == null || updateVersionString.compareTo(pendingAppUpdate.version) >= 0) {
pendingAppUpdate = null;
AndroidUtilities.runOnUIThread(SharedConfig::saveConfig);
}
@ -428,16 +435,29 @@ public class SharedConfig {
return pendingAppUpdateBuildVersion == currentVersion;
}
public static void setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) {
pendingAppUpdate = update;
public static boolean setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) {
String updateVersionString = null;
int versionCode = 0;
try {
PackageInfo packageInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
pendingAppUpdateBuildVersion = packageInfo.versionCode;
versionCode = packageInfo.versionCode;
updateVersionString = packageInfo.versionName;
} catch (Exception e) {
FileLog.e(e);
pendingAppUpdateBuildVersion = BuildVars.BUILD_VERSION;
}
if (versionCode == 0) {
versionCode = BuildVars.BUILD_VERSION;
}
if (updateVersionString == null) {
updateVersionString = BuildVars.BUILD_VERSION_STRING;
}
if (update.version == null || updateVersionString.compareTo(update.version) >= 0) {
return false;
}
pendingAppUpdate = update;
pendingAppUpdateBuildVersion = versionCode;
saveConfig();
return true;
}
public static boolean checkPasscode(String passcode) {

View file

@ -65,16 +65,6 @@ public class UserConfig extends BaseController {
public volatile byte[] savedSaltedPassword;
public volatile long savedPasswordTime;
public String tonEncryptedData;
public String tonPublicKey;
public int tonPasscodeType = -1;
public byte[] tonPasscodeSalt;
public long tonPasscodeRetryInMs;
public long tonLastUptimeMillis;
public int tonBadPasscodeTries;
public String tonKeyName;
public boolean tonCreationFinished;
private static volatile UserConfig[] Instance = new UserConfig[UserConfig.MAX_ACCOUNT_COUNT];
public static UserConfig getInstance(int num) {
UserConfig localInstance = Instance[num];
@ -146,21 +136,6 @@ public class UserConfig extends BaseController {
editor.putInt("sharingMyLocationUntil", sharingMyLocationUntil);
editor.putInt("lastMyLocationShareTime", lastMyLocationShareTime);
editor.putBoolean("filtersLoaded", filtersLoaded);
if (tonEncryptedData != null) {
editor.putString("tonEncryptedData", tonEncryptedData);
editor.putString("tonPublicKey", tonPublicKey);
editor.putString("tonKeyName", tonKeyName);
editor.putBoolean("tonCreationFinished", tonCreationFinished);
if (tonPasscodeSalt != null) {
editor.putInt("tonPasscodeType", tonPasscodeType);
editor.putString("tonPasscodeSalt", Base64.encodeToString(tonPasscodeSalt, Base64.DEFAULT));
editor.putLong("tonPasscodeRetryInMs", tonPasscodeRetryInMs);
editor.putLong("tonLastUptimeMillis", tonLastUptimeMillis);
editor.putInt("tonBadPasscodeTries", tonBadPasscodeTries);
}
} else {
editor.remove("tonEncryptedData").remove("tonPublicKey").remove("tonKeyName").remove("tonPasscodeType").remove("tonPasscodeSalt").remove("tonPasscodeRetryInMs").remove("tonBadPasscodeTries").remove("tonLastUptimeMillis").remove("tonCreationFinished");
}
editor.putInt("6migrateOffsetId", migrateOffsetId);
if (migrateOffsetId != -1) {
@ -282,25 +257,9 @@ public class UserConfig extends BaseController {
notificationsSignUpSettingsLoaded = preferences.getBoolean("notificationsSignUpSettingsLoaded", false);
autoDownloadConfigLoadTime = preferences.getLong("autoDownloadConfigLoadTime", 0);
hasValidDialogLoadIds = preferences.contains("2dialogsLoadOffsetId") || preferences.getBoolean("hasValidDialogLoadIds", false);
tonEncryptedData = preferences.getString("tonEncryptedData", null);
tonPublicKey = preferences.getString("tonPublicKey", null);
tonKeyName = preferences.getString("tonKeyName", "walletKey" + currentAccount);
tonCreationFinished = preferences.getBoolean("tonCreationFinished", true);
sharingMyLocationUntil = preferences.getInt("sharingMyLocationUntil", 0);
lastMyLocationShareTime = preferences.getInt("lastMyLocationShareTime", 0);
filtersLoaded = preferences.getBoolean("filtersLoaded", false);
String salt = preferences.getString("tonPasscodeSalt", null);
if (salt != null) {
try {
tonPasscodeSalt = Base64.decode(salt, Base64.DEFAULT);
tonPasscodeType = preferences.getInt("tonPasscodeType", -1);
tonPasscodeRetryInMs = preferences.getLong("tonPasscodeRetryInMs", 0);
tonLastUptimeMillis = preferences.getLong("tonLastUptimeMillis", 0);
tonBadPasscodeTries = preferences.getInt("tonBadPasscodeTries", 0);
} catch (Exception e) {
FileLog.e(e);
}
}
try {
String terms = preferences.getString("terms", null);
@ -388,21 +347,8 @@ public class UserConfig extends BaseController {
}
}
public void clearTonConfig() {
tonEncryptedData = null;
tonKeyName = null;
tonPublicKey = null;
tonPasscodeType = -1;
tonPasscodeSalt = null;
tonCreationFinished = false;
tonPasscodeRetryInMs = 0;
tonLastUptimeMillis = 0;
tonBadPasscodeTries = 0;
}
public void clearConfig() {
getPreferences().edit().clear().commit();
clearTonConfig();
sharingMyLocationUntil = 0;
lastMyLocationShareTime = 0;

View file

@ -644,9 +644,11 @@ public class ActionBarLayout extends FrameLayout {
public boolean onTouchEvent(MotionEvent ev) {
if (!checkTransitionAnimation() && !inActionMode && !animationInProgress) {
if (fragmentsStack.size() > 1) {
if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking) {
if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
if (!currentFragment.isSwipeBackEnabled(ev)) {
maybeStartTracking = false;
startedTracking = false;
return false;
}
startedTrackingPointerId = ev.getPointerId(0);

View file

@ -358,7 +358,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback {
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.copyFrom(window.getAttributes());
params.width = Math.min(maxWidth, calculatedWidth) + backgroundPaddings.left + backgroundPaddings.right;
window.setAttributes(params);
try {
window.setAttributes(params);
} catch (Throwable e) {
FileLog.e(e);
}
});
}
}

View file

@ -7369,7 +7369,7 @@ public class Theme {
}
}
public static void createCommonChatResources(Context context) {
public static void createCommonChatResources() {
synchronized (sync) {
if (chat_msgTextPaint == null) {
chat_msgTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
@ -7466,7 +7466,7 @@ public class Theme {
}
public static void createChatResources(Context context, boolean fontsOnly) {
createCommonChatResources(context);
createCommonChatResources();
if (!fontsOnly && chat_msgInDrawable == null) {
@ -8687,6 +8687,7 @@ public class Theme {
Drawable drawable = wallpaper;
AndroidUtilities.runOnUIThread(() -> {
wallpaperLoadTask = null;
createCommonChatResources();
applyChatServiceMessageColor(null, null, drawable);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper);
});

View file

@ -8028,10 +8028,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
if (firstVisibleBlockNum >= 0) {
int restore = Integer.MIN_VALUE;
int oldAlpha = -1;
int oldLinkAlpha = -1;
if (alpha != 1.0f) {
if (drawOnlyText) {
oldAlpha = Theme.chat_msgTextPaint.getAlpha();
oldLinkAlpha = Color.alpha(Theme.chat_msgTextPaint.linkColor);
Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * alpha));
Theme.chat_msgTextPaint.linkColor = ColorUtils.setAlphaComponent(Theme.chat_msgTextPaint.linkColor, (int) (oldLinkAlpha * alpha));
} else {
if (currentBackgroundDrawable != null) {
int top = currentBackgroundDrawable.getBounds().top;
@ -8083,6 +8086,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
}
if (oldAlpha >= 0) {
Theme.chat_msgTextPaint.setAlpha(oldAlpha);
Theme.chat_msgTextPaint.linkColor = ColorUtils.setAlphaComponent(Theme.chat_msgTextPaint.linkColor, oldLinkAlpha);
}
if (restore != Integer.MIN_VALUE) {
@ -9817,6 +9821,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate
return;
}
Theme.MessageDrawable drawable = a == 0 ? currentBackgroundDrawable : currentBackgroundSelectedDrawable;
if (drawable == null) {
continue;
}
int h = parentHeight;
if (h == 0) {
h = AndroidUtilities.displaySize.y;

View file

@ -3102,8 +3102,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
}
if (!SharedConfig.smoothKeyboard) {
setBottomClip(paddingBottom);
} else if (!inPreviewMode) {
} else if (!inPreviewMode && chatActivityEnterView.getEmojiPadding() == 0) {
setBottomClip(AndroidUtilities.dp(48));
} else {
setBottomClip(0);
}
for (int i = 0; i < count; i++) {
@ -6936,13 +6938,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
searchUpButton.setOnClickListener(view -> {
getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, threadMessageId, searchingUserMessages, searchingChatMessages);
showMessagesSearchListView(false);
//if (!SharedConfig.searchMessagesAsListUsed && SharedConfig.searchMessagesAsListHintShows < 3 && !searchAsListHintShown && Math.random() <= 0.25) {
if (!searchAsListHintShown) {
if (!SharedConfig.searchMessagesAsListUsed && SharedConfig.searchMessagesAsListHintShows < 3 && !searchAsListHintShown && Math.random() <= 0.25) {
showSearchAsListHint();
// searchAsListHintShown = true;
searchAsListHintShown = true;
SharedConfig.increaseSearchAsListHintShows();
}
// SharedConfig.increaseSearchAsListHintShows();
// }
});
searchUpButton.setContentDescription(LocaleController.getString("AccDescrSearchNext", R.string.AccDescrSearchNext));
@ -6997,9 +6997,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
searchCalendarButton.setContentDescription(LocaleController.getString("JumpToDate", R.string.JumpToDate));
searchCountText = new SearchCounterView(context);
// searchCountText.setTextColor(Theme.getColor(Theme.key_chat_searchPanelText));
// searchCountText.setTextSize(15);
// searchCountText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
searchCountText.setGravity(Gravity.LEFT);
searchContainer.addView(searchCountText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 108, 0));

View file

@ -25,7 +25,7 @@ public class ChatsWidgetConfigActivity extends ExternalActionActivity {
args.putBoolean("onlySelect", true);
args.putInt("dialogsType", 10);
args.putBoolean("allowSwitchAccount", true);
EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CHATS, creatingAppWidgetId, false);
EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CHATS, creatingAppWidgetId);
fragment.setDelegate(dialogs -> {
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, creatingAppWidgetId);

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
@ -31,6 +32,7 @@ import java.util.ArrayList;
public class BotCommandsMenuView extends View {
final RectF rectTmp = new RectF();
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
final MenuDrawable backDrawable = new MenuDrawable() {
@ -74,7 +76,7 @@ public class BotCommandsMenuView extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = MeasureSpec.getSize(widthMeasureSpec) + MeasureSpec.getSize(heightMeasureSpec) << 16;
if (lastSize != size) {
if (lastSize != size || menuText == null) {
backDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
textPaint.setTextSize(AndroidUtilities.dp(15));
lastSize = size;
@ -93,49 +95,49 @@ public class BotCommandsMenuView extends View {
@Override
protected void dispatchDraw(Canvas canvas) {
boolean update = false;
if (expanded && expandProgress != 1f) {
expandProgress += 16f / 150f;
if (expandProgress > 1) {
expandProgress = 1f;
} else {
invalidate();
if (menuText != null) {
boolean update = false;
if (expanded && expandProgress != 1f) {
expandProgress += 16f / 150f;
if (expandProgress > 1) {
expandProgress = 1f;
} else {
invalidate();
}
update = true;
} else if (!expanded && expandProgress != 0) {
expandProgress -= 16f / 150f;
if (expandProgress < 0) {
expandProgress = 0;
} else {
invalidate();
}
update = true;
}
update = true;
} else if (!expanded && expandProgress != 0) {
expandProgress -= 16f / 150f;
if (expandProgress < 0) {
expandProgress = 0;
} else {
invalidate();
float expandProgress = CubicBezierInterpolator.DEFAULT.getInterpolation(this.expandProgress);
if (update && expandProgress > 0) {
textPaint.setAlpha((int) (255 * expandProgress));
}
update = true;
}
float expandProgress = CubicBezierInterpolator.DEFAULT.getInterpolation(this.expandProgress);
if (update && expandProgress > 0) {
textPaint.setAlpha((int) (255 * expandProgress));
}
AndroidUtilities.rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight());
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint);
backgroundDrawable.setBounds((int) AndroidUtilities.rectTmp.left, (int) AndroidUtilities.rectTmp.top, (int) AndroidUtilities.rectTmp.right, (int) AndroidUtilities.rectTmp.bottom);
backgroundDrawable.draw(canvas);
canvas.save();
canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4));
backDrawable.draw(canvas);
canvas.restore();
if (expandProgress > 0) {
rectTmp.set(0, 0, AndroidUtilities.dp(40) + (menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress, getMeasuredHeight());
canvas.drawRoundRect(rectTmp, AndroidUtilities.dp(16), AndroidUtilities.dp(16), paint);
backgroundDrawable.setBounds((int) rectTmp.left, (int) rectTmp.top, (int) rectTmp.right, (int) rectTmp.bottom);
backgroundDrawable.draw(canvas);
canvas.save();
canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuText.getHeight()) / 2f);
menuText.draw(canvas);
canvas.translate(AndroidUtilities.dp(8), AndroidUtilities.dp(4));
backDrawable.draw(canvas);
canvas.restore();
}
if (update) {
onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress);
if (expandProgress > 0) {
canvas.save();
canvas.translate(AndroidUtilities.dp(34), (getMeasuredHeight() - menuText.getHeight()) / 2f);
menuText.draw(canvas);
canvas.restore();
}
if (update) {
onTranslationChanged((menuText.getWidth() + AndroidUtilities.dp(4)) * expandProgress);
}
}
super.dispatchDraw(canvas);
}

View file

@ -144,8 +144,6 @@ import java.util.Locale;
public class ChatActivityEnterView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, StickersAlert.StickersAlertDelegate {
boolean textTransitionIsRunning;
public interface ChatActivityEnterViewDelegate {
void onMessageSend(CharSequence message, boolean notify, int scheduleDate);
@ -243,6 +241,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
private Runnable moveToSendStateRunnable;
boolean messageTransitionIsRunning;
boolean textTransitionIsRunning;
private BotCommandsMenuView botCommandsMenuButton;
public BotCommandsMenuContainer botCommandsMenuContainer;
@ -4121,7 +4120,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
}
}
if (processSendingText(message, notify, scheduleDate)) {
if (delegate.hasForwardingMessages()) {
if (delegate.hasForwardingMessages() || (scheduleDate != 0 && !isInScheduleMode()) || isInScheduleMode()) {
messageEditText.setText("");
if (delegate != null) {
delegate.onMessageSend(message, notify, scheduleDate);

View file

@ -2874,7 +2874,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou
@Override
public boolean onSheetKeyDown(int keyCode, KeyEvent event) {
if (cameraOpened && (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
if (cameraOpened && (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)) {
shutterButton.getDelegate().shutterReleased();
return true;
}

View file

@ -209,6 +209,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
float pinchScale;
boolean isInPinchToZoomTouchMode;
boolean maybePinchToZoomTouchMode;
private int pointerId1, pointerId2;
@ -2497,7 +2498,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
}
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
if (!isInPinchToZoomTouchMode && ev.getPointerCount() == 2 && finishZoomTransition == null && recording) {
if (maybePinchToZoomTouchMode && !isInPinchToZoomTouchMode && ev.getPointerCount() == 2 && finishZoomTransition == null && recording) {
pinchStartDistance = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0));
pinchScale = 1f;
@ -2508,7 +2509,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
}
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
AndroidUtilities.rectTmp.set(cameraContainer.getX(), cameraContainer.getY(), cameraContainer.getX() + cameraContainer.getMeasuredWidth(), cameraContainer.getY() + cameraContainer.getMeasuredHeight());
return AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY());
maybePinchToZoomTouchMode = AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY());
}
return true;
} else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && isInPinchToZoomTouchMode) {
@ -2536,7 +2537,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
isInPinchToZoomTouchMode = false;
finishZoom();
}
return isInPinchToZoomTouchMode;
return true;
}
ValueAnimator finishZoomTransition;

View file

@ -314,7 +314,7 @@ public class MotionBackgroundDrawable extends Drawable {
if (Build.VERSION.SDK_INT < 28 && intensity < 0) {
int w = right - left;
int h = bottom - top;
if (legacyBitmap == null || legacyBitmap.getWidth() != w || legacyBitmap.getHeight() != h) {
if (w > 0 && h > 0 && (legacyBitmap == null || legacyBitmap.getWidth() != w || legacyBitmap.getHeight() != h)) {
if (legacyBitmap != null) {
legacyBitmap.recycle();
}

View file

@ -1090,14 +1090,22 @@ public class PasscodeView extends FrameLayout {
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.from(ApplicationLoader.applicationContext);
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
fingerprintView.setVisibility(VISIBLE);
} else {
fingerprintView.setVisibility(GONE);
}
} catch (Throwable e) {
FileLog.e(e);
fingerprintView.setVisibility(GONE);
}
} else {
fingerprintView.setVisibility(GONE);
}
if (SharedConfig.passcodeType == 1) {
fingerprintImage.setVisibility(fingerprintView.getVisibility());
}
if (numberFrameLayouts.size() >= 11) {
numberFrameLayouts.get(11).setVisibility(fingerprintView.getVisibility());
}
}
public void onShow(boolean fingerprint, boolean animated, int x, int y, Runnable onShow, Runnable onStart) {
@ -1363,7 +1371,7 @@ public class PasscodeView extends FrameLayout {
layoutParams = (LayoutParams) numbersFrameLayout.getLayoutParams();
layoutParams.height = height;
layoutParams.leftMargin = width / 2;
layoutParams.topMargin = height - layoutParams.height;
layoutParams.topMargin = height - layoutParams.height + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0);
layoutParams.width = width / 2;
numbersFrameLayout.setLayoutParams(layoutParams);
} else {
@ -1390,10 +1398,10 @@ public class PasscodeView extends FrameLayout {
passwordFrameLayout.setLayoutParams(layoutParams);
layoutParams = (LayoutParams) numbersFrameLayout.getLayoutParams();
layoutParams.height = height / 3 * 2 + AndroidUtilities.dp(20);
layoutParams.height = height / 3 * 2;
layoutParams.leftMargin = left;
if (AndroidUtilities.isTablet()) {
layoutParams.topMargin = height - layoutParams.height + top;
layoutParams.topMargin = height - layoutParams.height + top + AndroidUtilities.dp(20);
} else {
layoutParams.topMargin = height - layoutParams.height + top + (SharedConfig.passcodeType == 0 ? AndroidUtilities.dp(40) : 0);
}

View file

@ -237,13 +237,13 @@ public class SearchCounterView extends View {
boolean increment = countAnimationIncrement;
if (countAnimationInLayout != null) {
canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
canvas.translate(countLeft, countTop + AndroidUtilities.dp(2) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
textPaint.setAlpha((int) (255 * countChangeProgress));
countAnimationInLayout.draw(canvas);
canvas.restore();
} else if (countLayout != null) {
canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
canvas.translate(countLeft, countTop + AndroidUtilities.dp(2) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
textPaint.setAlpha((int) (255 * countChangeProgress));
countLayout.draw(canvas);
canvas.restore();
@ -251,7 +251,7 @@ public class SearchCounterView extends View {
if (countOldLayout != null) {
canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? -AndroidUtilities.dp(13) : AndroidUtilities.dp(13)) * (countChangeProgress));
canvas.translate(countLeft, countTop + AndroidUtilities.dp(2) + (increment ? -AndroidUtilities.dp(13) : AndroidUtilities.dp(13)) * (countChangeProgress));
textPaint.setAlpha((int) (255 * (1f - countChangeProgress)));
countOldLayout.draw(canvas);
canvas.restore();
@ -259,7 +259,7 @@ public class SearchCounterView extends View {
if (countAnimationStableLayout != null) {
canvas.save();
canvas.translate(countLeft + dx * (1f - countChangeProgress), countTop + AndroidUtilities.dp(4));
canvas.translate(countLeft + dx * (1f - countChangeProgress), countTop + AndroidUtilities.dp(2));
textPaint.setAlpha(255);
countAnimationStableLayout.draw(canvas);
canvas.restore();
@ -267,7 +267,7 @@ public class SearchCounterView extends View {
if (countAnimationStableLayout2 != null) {
canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
canvas.translate(countLeft, countTop + AndroidUtilities.dp(2));
textPaint.setAlpha(255);
countAnimationStableLayout2.draw(canvas);
canvas.restore();
@ -299,7 +299,7 @@ public class SearchCounterView extends View {
updateX(countWidth);
if (countLayout != null) {
canvas.save();
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
canvas.translate(countLeft, countTop + AndroidUtilities.dp(2));
countLayout.draw(canvas);
canvas.restore();
}

View file

@ -254,18 +254,20 @@ public class GroupCallMiniTextureView extends FrameLayout implements GroupCallSt
if (animateToFullscreen || showingInFullscreen) {
size += (AndroidUtilities.dp(10) + AndroidUtilities.dp(39) * parentContainer.progressToFullscreenMode);
} else {
size += AndroidUtilities.dp(10) * (1.0f - parentContainer.progressToFullscreenMode);
size += AndroidUtilities.dp(10) * Math.max(1.0f - parentContainer.progressToFullscreenMode, showingAsScrimView || animateToScrimView ? parentContainer.progressToScrimView : 0.0f);
}
int x = (getMeasuredWidth() - size) / 2;
float smallProgress;
float smallProgress2;
float scrimProgress = (showingAsScrimView || animateToScrimView ? parentContainer.progressToScrimView : 0);
if (showingInFullscreen) {
smallProgress = progressToFullscreen;
smallProgress = smallProgress2 = progressToFullscreen;
} else {
smallProgress = animateToFullscreen ? parentContainer.progressToFullscreenMode : scrimProgress;
smallProgress2 = showingAsScrimView || animateToScrimView ? parentContainer.progressToScrimView : parentContainer.progressToFullscreenMode;
}
int y = (int) ((getMeasuredHeight() - size) / 2 - AndroidUtilities.dp(11) - (AndroidUtilities.dp(17) + AndroidUtilities.dp(74) * parentContainer.progressToFullscreenMode) * smallProgress);
int y = (int) ((getMeasuredHeight() - size) / 2 - AndroidUtilities.dp(28) - (AndroidUtilities.dp(17) + AndroidUtilities.dp(74) * (showingInFullscreen || animateToFullscreen ? parentContainer.progressToFullscreenMode : 0.0f)) * smallProgress + AndroidUtilities.dp(17) * smallProgress2);
castingScreenDrawable.setBounds(x, y, x + size, y + size);
castingScreenDrawable.draw(canvas);
@ -1102,8 +1104,14 @@ public class GroupCallMiniTextureView extends FrameLayout implements GroupCallSt
}
boolean pausedInternal = false;
if (participant.participant.video != null && participant.participant.video.paused) {
pausedInternal = true;
if (participant.presentation) {
if (participant.participant.presentation != null && participant.participant.presentation.paused) {
pausedInternal = true;
}
} else {
if (participant.participant.video != null && participant.participant.video.paused) {
pausedInternal = true;
}
}
if (videoIsPaused != pausedInternal) {
videoIsPaused = pausedInternal;

View file

@ -25,7 +25,7 @@ public class ContactsWidgetConfigActivity extends ExternalActionActivity {
args.putBoolean("onlySelect", true);
args.putInt("dialogsType", 10);
args.putBoolean("allowSwitchAccount", true);
EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CONTACTS, creatingAppWidgetId, false);
EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CONTACTS, creatingAppWidgetId);
fragment.setDelegate(dialogs -> {
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, creatingAppWidgetId);

View file

@ -104,7 +104,6 @@ public class EditWidgetActivity extends BaseFragment {
private int widgetType;
private int currentWidgetId;
private boolean isEdit;
private EditWidgetActivityDelegate delegate;
@ -733,18 +732,15 @@ public class EditWidgetActivity extends BaseFragment {
}
}
public EditWidgetActivity(int type, int widgetId, boolean edit) {
public EditWidgetActivity(int type, int widgetId) {
super();
widgetType = type;
currentWidgetId = widgetId;
isEdit = edit;
if (edit) {
ArrayList<TLRPC.User> users = new ArrayList<>();
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
getMessagesStorage().getWidgetDialogIds(currentWidgetId, widgetType, selectedDialogs, users, chats, true);
getMessagesController().putUsers(users, true);
getMessagesController().putChats(chats, true);
}
ArrayList<TLRPC.User> users = new ArrayList<>();
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
getMessagesStorage().getWidgetDialogIds(currentWidgetId, widgetType, selectedDialogs, users, chats, true);
getMessagesController().putUsers(users, true);
getMessagesController().putChats(chats, true);
updateRows();
}
@ -810,14 +806,16 @@ public class EditWidgetActivity extends BaseFragment {
getMessagesStorage().putWidgetDialogs(currentWidgetId, selectedDialogs);
SharedPreferences preferences = getParentActivity().getSharedPreferences("shortcut_widget", Activity.MODE_PRIVATE);
preferences.edit().putInt("account" + currentWidgetId, currentAccount).commit();
preferences.edit().putInt("type" + currentWidgetId, widgetType).commit();
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("account" + currentWidgetId, currentAccount);
editor.putInt("type" + currentWidgetId, widgetType);
editor.commit();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getParentActivity());
if (widgetType == TYPE_CHATS) {
ChatsWidgetProvider.updateWidget(getParentActivity(), appWidgetManager, currentWidgetId, isEdit);
ChatsWidgetProvider.updateWidget(getParentActivity(), appWidgetManager, currentWidgetId);
} else {
ContactsWidgetProvider.updateWidget(getParentActivity(), appWidgetManager, currentWidgetId, isEdit);
ContactsWidgetProvider.updateWidget(getParentActivity(), appWidgetManager, currentWidgetId);
}
if (delegate != null) {
delegate.didSelectDialogs(selectedDialogs);

View file

@ -35,8 +35,10 @@ public class FeedWidgetConfigActivity extends ExternalActionActivity {
AccountInstance.getInstance(fragment1.getCurrentAccount()).getMessagesStorage().putWidgetDialogs(creatingAppWidgetId, dids);
SharedPreferences preferences = FeedWidgetConfigActivity.this.getSharedPreferences("shortcut_widget", Activity.MODE_PRIVATE);
preferences.edit().putInt("account" + creatingAppWidgetId, fragment1.getCurrentAccount()).commit();
preferences.edit().putLong("dialogId" + creatingAppWidgetId, dids.get(0)).commit();
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("account" + creatingAppWidgetId, fragment1.getCurrentAccount());
editor.putLong("dialogId" + creatingAppWidgetId, dids.get(0));
editor.commit();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(FeedWidgetConfigActivity.this);
FeedWidgetProvider.updateWidget(FeedWidgetConfigActivity.this, appWidgetManager, creatingAppWidgetId);

View file

@ -308,7 +308,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
if (Build.VERSION.SDK_INT >= 24) {
AndroidUtilities.isInMultiwindow = isInMultiWindowMode();
}
Theme.createCommonChatResources(this);
Theme.createCommonChatResources();
Theme.createDialogsResources(this);
if (SharedConfig.passcodeHash.length() != 0 && SharedConfig.appLocked) {
SharedConfig.lastPauseTime = (int) (SystemClock.elapsedRealtime() / 1000);
@ -2273,7 +2273,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
fragment = new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_CHANGE_PHONE_NUMBER);
closePrevious = true;
} else if (open_settings == 6) {
fragment = new EditWidgetActivity(open_widget_edit_type, open_widget_edit, true);
fragment = new EditWidgetActivity(open_widget_edit_type, open_widget_edit);
} else {
fragment = null;
}
@ -3657,18 +3657,19 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
if (SharedConfig.pendingAppUpdate != null && SharedConfig.pendingAppUpdate.version.equals(res.version)) {
return;
}
SharedConfig.setNewAppVersionAvailable(res);
if (res.can_not_skip) {
showUpdateActivity(accountNum, res, false);
} else {
drawerLayoutAdapter.notifyDataSetChanged();
try {
(new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show();
} catch (Exception e) {
FileLog.e(e);
if (SharedConfig.setNewAppVersionAvailable(res)) {
if (res.can_not_skip) {
showUpdateActivity(accountNum, res, false);
} else {
drawerLayoutAdapter.notifyDataSetChanged();
try {
(new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show();
} catch (Exception e) {
FileLog.e(e);
}
}
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.appUpdateAvailable);
}
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.appUpdateAvailable);
});
}
});

View file

@ -676,7 +676,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
BulletinFactory.of(containerView).createSimpleBulletin(R.raw.voip_invite, bulletinMessage).show();
}
});
builder.create().show();
BottomSheet bottomSheet = builder.create();
bottomSheet.show();
bottomSheet.setItemColor(0,0xffffffff, 0xffffffff);
bottomSheet.setItemColor(1,0xffffffff, 0xffffffff);
bottomSheet.setBackgroundColor(0xff1C2229);
bottomSheet.setTitleColor(0xff8A8A8A);
}
}

View file

@ -1480,6 +1480,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
@Override
public View createView(Context context) {
Theme.createProfileResources(context);
Theme.createChatResources(context, false);
searchTransitionOffset = 0;
searchTransitionProgress = 1f;

View file

@ -16,6 +16,7 @@ import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.StaticLayout;
import android.text.TextPaint;
@ -114,6 +115,9 @@ public class TextMessageEnterTransition implements MessageEnterTransitionContain
enterView = chatActivity.getChatActivityEnterView();
ChatActivityEnterView chatActivityEnterView = chatActivity.getChatActivityEnterView();
if (chatActivityEnterView == null || chatActivityEnterView.getEditField() == null || chatActivityEnterView.getEditField().getLayout() == null) {
return;
}
fromRadius = chatActivityEnterView.getRecordCicle().drawingCircleRadius;
bitmapPaint.setFilterBitmap(true);
@ -145,7 +149,18 @@ public class TextMessageEnterTransition implements MessageEnterTransitionContain
emojiSize = AndroidUtilities.dp(24);
}
}
if (editText.length() != text.length()) {
boolean containsSpans = false;
if (text instanceof Spannable) {
Spannable spannable = (Spannable) text;
Object[] objects = spannable.getSpans(0, text.length(), Object.class);
for (int i = 0; i < objects.length; i++) {
if (!(objects[i] instanceof Emoji.EmojiSpan)) {
containsSpans = true;
break;
}
}
}
if (editText.length() != text.length() || containsSpans) {
crossfade = true;
String str = editText.toString();
String trimmedStr = str.trim();
@ -543,78 +558,78 @@ public class TextMessageEnterTransition implements MessageEnterTransitionContain
}
canvas.save();
{
canvas.clipRect(drawableX + AndroidUtilities.dp(4), drawableTop + AndroidUtilities.dp(4), drawableRight - AndroidUtilities.dp(4), drawableBottom - AndroidUtilities.dp(4));
float scale = progressX + scaleFrom * (1f - progressX);
float scale2;
if (drawBitmaps) {
scale2 = progressX + scaleY * (1f - progressX);
canvas.clipRect(drawableX + AndroidUtilities.dp(4), drawableTop + AndroidUtilities.dp(4), drawableRight - AndroidUtilities.dp(4), drawableBottom - AndroidUtilities.dp(4));
float scale = progressX + scaleFrom * (1f - progressX);
float scale2;
if (drawBitmaps) {
scale2 = progressX + scaleY * (1f - progressX);
} else {
scale2 = 1f;
}
canvas.save();
canvas.translate(fromX * (1f - progressX) + (toX - toXOffset) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
canvas.scale(scale, scale * scale2, 0, 0);
// canvas.translate(0, textLayoutBlock.textYOffset / 2);
if (drawBitmaps) {
if (crossfade) {
bitmapPaint.setAlpha((int) (255 * (1f - alphaProgress)));
}
canvas.drawBitmap(textLayoutBitmap, 0, 0, bitmapPaint);
} else {
if (crossfade) {
int oldAlpha = Theme.chat_msgTextPaint.getAlpha();
Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * (1f - alphaProgress)));
layout.draw(canvas);
Theme.chat_msgTextPaint.setAlpha(oldAlpha);
} else {
scale2 = 1f;
layout.draw(canvas);
}
}
canvas.restore();
if (rtlLayout != null) {
canvas.save();
canvas.translate(fromX * (1f - progressX) + (toX - toXOffset) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
canvas.translate(fromX * (1f - progressX) + (toX - toXOffsetRtl) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
canvas.scale(scale, scale * scale2, 0, 0);
// canvas.translate(0, textLayoutBlock.textYOffset / 2);
if (drawBitmaps) {
if (crossfade) {
bitmapPaint.setAlpha((int) (255 * (1f - alphaProgress)));
}
canvas.drawBitmap(textLayoutBitmap, 0, 0, bitmapPaint);
canvas.drawBitmap(textLayoutBitmapRtl, 0, 0, bitmapPaint);
} else {
if (crossfade) {
int oldAlpha = Theme.chat_msgTextPaint.getAlpha();
Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * (1f - alphaProgress)));
layout.draw(canvas);
rtlLayout.draw(canvas);
Theme.chat_msgTextPaint.setAlpha(oldAlpha);
} else {
layout.draw(canvas);
rtlLayout.draw(canvas);
}
}
canvas.restore();
if (rtlLayout != null) {
canvas.save();
canvas.translate(fromX * (1f - progressX) + (toX - toXOffsetRtl) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
canvas.scale(scale, scale * scale2, 0, 0);
if (drawBitmaps) {
if (crossfade) {
bitmapPaint.setAlpha((int) (255 * (1f - alphaProgress)));
}
canvas.drawBitmap(textLayoutBitmapRtl, 0, 0, bitmapPaint);
} else {
if (crossfade) {
int oldAlpha = Theme.chat_msgTextPaint.getAlpha();
Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * (1f - alphaProgress)));
rtlLayout.draw(canvas);
Theme.chat_msgTextPaint.setAlpha(oldAlpha);
} else {
rtlLayout.draw(canvas);
}
}
canvas.restore();
}
if (crossfade) {
canvas.save();
canvas.translate(messageView.getLeft() + listView.getX() - container.getX() + (fromX - toX) * (1f - progressX), messageViewY + (fromY - toY) * (1f - progress));
canvas.scale(scale, scale * scale2, messageView.getTextX(), messageView.getTextY());
canvas.translate(0, -crossfadeTextOffset);
if (drawBitmaps) {
bitmapPaint.setAlpha((int) (255 * alphaProgress));
canvas.drawBitmap(crossfadeTextBitmap, 0, 0, bitmapPaint);
} else {
messageView.drawMessageText(canvas, messageView.getMessageObject().textLayoutBlocks, true, alphaProgress, true);
}
canvas.restore();
}
}
if (crossfade) {
canvas.save();
canvas.translate(messageView.getLeft() + listView.getX() - container.getX() + (fromX - toX) * (1f - progressX), messageViewY + (fromY - toY) * (1f - progress));
canvas.scale(scale, scale * scale2, messageView.getTextX(), messageView.getTextY());
canvas.translate(0, -crossfadeTextOffset);
if (crossfadeTextBitmap != null) {
bitmapPaint.setAlpha((int) (255 * alphaProgress));
canvas.drawBitmap(crossfadeTextBitmap, 0, 0, bitmapPaint);
} else {
messageView.drawMessageText(canvas, messageView.getMessageObject().textLayoutBlocks, true, alphaProgress, true);
}
canvas.restore();
}
canvas.restore();
if (clipBottomWithAlpha) {
@ -631,8 +646,8 @@ public class TextMessageEnterTransition implements MessageEnterTransitionContain
}
if (enterView.getSendButton().getVisibility() == View.VISIBLE && sendProgress < 1f) {
canvas.save();
canvas.translate(enterView.getX() + enterView.getSendButton().getX() + ((View) enterView.getSendButton().getParent()).getX() + ((View) enterView.getSendButton().getParent().getParent()).getX() - container.getX() + AndroidUtilities.dp(52) * sendProgress, enterView.getY() + enterView.getSendButton().getY() + ((View) enterView.getSendButton().getParent()).getY() + ((View) enterView.getSendButton().getParent().getParent()).getY()- container.getY());
// canvas.saveLayerAlpha(0, 0, enterView.getSendButton().getWidth(), enterView.getSendButton().getHeight(), (int) (enterView.getSendButton().getAlpha() * 255), Canvas.ALL_SAVE_FLAG);
canvas.translate(enterView.getX() + enterView.getSendButton().getX() + ((View) enterView.getSendButton().getParent()).getX() + ((View) enterView.getSendButton().getParent().getParent()).getX() - container.getX() + AndroidUtilities.dp(52) * sendProgress, enterView.getY() + enterView.getSendButton().getY() + ((View) enterView.getSendButton().getParent()).getY() + ((View) enterView.getSendButton().getParent().getParent()).getY() - container.getY());
// canvas.saveLayerAlpha(0, 0, enterView.getSendButton().getWidth(), enterView.getSendButton().getHeight(), (int) (enterView.getSendButton().getAlpha() * 255), Canvas.ALL_SAVE_FLAG);
//canvas.scale(enterView.getSendButton().getScaleX(), enterView.getSendButton().getScaleY(), enterView.getSendButton().getWidth() / 2f, enterView.getSendButton().getHeight() / 2f);
enterView.getSendButton().draw(canvas);
canvas.restore();

View file

@ -29,7 +29,7 @@ public class VoIPPermissionActivity extends Activity {
if (isVideoCall && checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.CAMERA);
}
if (permissions.isEmpty()) {
if (!permissions.isEmpty()) {
try {
requestPermissions(permissions.toArray(new String[0]), isVideoCall ? 102 : 101);
} catch (Exception e) {

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/widgetBackgroundCornerRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/colorAccent" />
<corners
android:topLeftRadius="12dp"
android:topRightRadius="12dp"
android:bottomLeftRadius="12dp"
android:bottomRightRadius="12dp"/>
</shape>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/colorButtonNormal" />
<corners
android:topLeftRadius="12dp"
android:topRightRadius="12dp"
android:bottomLeftRadius="12dp"
android:bottomRightRadius="12dp"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/widget_counter" />

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/widget_counter_muted" />

View file

@ -1,121 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:minHeight="72dp"
android:id="@+id/contacts_widget_item"
android:layout_width="match_parent"
android:layout_height="86dp"
android:weightSum="1"
android:baselineAligned="false">
android:baselineAligned="false"
android:minHeight="72dp"
android:orientation="horizontal"
android:weightSum="1">
<FrameLayout
android:layout_width="0dp"
android:id="@+id/contacts_widget_item1"
android:layout_height="86dp"
android:background="@drawable/list_selector_ex"
android:layout_weight="0.5">
<include layout="@layout/contacts_widget_item_1" />
<ImageView android:id="@+id/contacts_widget_item_avatar1"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:gravity="start" />
<include layout="@layout/contacts_widget_item_2" />
<TextView android:id="@+id/contacts_widget_item_text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_gravity="center"
android:textSize="12dp"
android:layout_marginRight="6dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="28dp"
android:textColor="@color/widget_name"/>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="1dp"
android:background="@drawable/widgets_light_badgebg"
android:layout_gravity="center"
android:layout_marginBottom="27dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="4dp"
android:id="@+id/contacts_widget_item_badge_bg1">
<TextView android:id="@+id/contacts_widget_item_badge1"
android:layout_width="wrap_content"
android:layout_height="23dp"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:paddingBottom="1dp"
android:fontFamily="sans-serif-medium"
android:layout_gravity="center"
android:gravity="center"
android:minWidth="23dp"
android:textSize="13dp"
android:background="@drawable/widget_counter"
android:textColor="@color/widget_badge" />
</FrameLayout>
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:minHeight="72dp"
android:id="@+id/contacts_widget_item2"
android:background="@drawable/list_selector_ex"
android:layout_height="86dp"
android:layout_weight="0.5">
<ImageView android:id="@+id/contacts_widget_item_avatar2"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:gravity="start" />
<TextView android:id="@+id/contacts_widget_item_text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_gravity="center"
android:textSize="12dp"
android:layout_marginRight="6dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="28dp"
android:textColor="@color/widget_name"/>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="1dp"
android:background="@drawable/widgets_light_badgebg"
android:layout_gravity="center"
android:layout_marginBottom="27dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="4dp"
android:id="@+id/contacts_widget_item_badge_bg2">
<TextView android:id="@+id/contacts_widget_item_badge2"
android:layout_width="wrap_content"
android:layout_height="23dp"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:paddingBottom="1dp"
android:fontFamily="sans-serif-medium"
android:layout_gravity="center"
android:gravity="center"
android:minWidth="23dp"
android:textSize="13dp"
android:background="@drawable/widget_counter"
android:textColor="@color/widget_badge" />
</FrameLayout>
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="0dp"
android:id="@+id/contacts_widget_item1"
android:layout_height="86dp"
android:background="@drawable/list_selector_ex"
android:layout_weight="0.5"
android:theme="@style/Theme.TMessages.AppWidget"
tools:showIn="@layout/contacts_widget_item">
<ImageView
android:id="@+id/contacts_widget_item_avatar1"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:src="?attr/widgetPreviewImage"
android:gravity="start" />
<TextView
android:id="@+id/contacts_widget_item_text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_gravity="center"
android:textSize="12dp"
android:layout_marginRight="6dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="28dp"
android:text="?attr/widgetPreviewTitle"
android:textColor="@color/widget_name" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="1dp"
android:background="@drawable/widgets_light_badgebg"
android:layout_gravity="center"
android:layout_marginBottom="27dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="4dp"
android:visibility="?attr/widgetPreviewDot"
android:id="@+id/contacts_widget_item_badge_bg1">
<TextView
android:id="@+id/contacts_widget_item_badge1"
style="@style/TMessages.AppWidget.Badge"
android:layout_gravity="center"
android:text="2" />
</FrameLayout>
</FrameLayout>

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="0dp"
android:minHeight="72dp"
android:id="@+id/contacts_widget_item2"
android:background="@drawable/list_selector_ex"
android:layout_height="86dp"
android:layout_weight="0.5"
android:theme="@style/Theme.TMessages.AppWidget"
tools:showIn="@layout/contacts_widget_item">
<ImageView
android:id="@+id/contacts_widget_item_avatar2"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:src="?attr/widgetPreviewImage"
android:gravity="start" />
<TextView
android:id="@+id/contacts_widget_item_text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_gravity="center"
android:textSize="12dp"
android:layout_marginRight="6dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="28dp"
android:text="?attr/widgetPreviewTitle"
android:textColor="@color/widget_name" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="1dp"
android:background="@drawable/widgets_light_badgebg"
android:layout_gravity="center"
android:layout_marginBottom="27dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="4dp"
android:visibility="?attr/widgetPreviewDot"
android:id="@+id/contacts_widget_item_badge_bg2">
<TextView
android:id="@+id/contacts_widget_item_badge2"
style="@style/TMessages.AppWidget.Badge"
android:layout_gravity="center"
android:text="1" />
</FrameLayout>
</FrameLayout>

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="90dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="176dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="262dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="348dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="176dp"
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include
layout="@layout/contacts_widget_item_1"
android:theme="@style/Theme.TMessages.AppWidget.Preview4" />
<include
layout="@layout/contacts_widget_item_2"
android:theme="@style/Theme.TMessages.AppWidget.Preview5" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<include
layout="@layout/contacts_widget_item_2"
android:theme="@style/Theme.TMessages.AppWidget.Preview6" />
<include
layout="@layout/contacts_widget_item_2"
android:theme="@style/Theme.TMessages.AppWidget.Preview7" />
</LinearLayout>
</LinearLayout>

View file

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:minHeight="72dp"
android:id="@+id/shortcut_widget_item"
android:layout_height="72dp">
android:layout_width="match_parent"
android:layout_height="72dp"
android:minHeight="72dp"
android:theme="@style/Theme.TMessages.AppWidget">
<ImageView android:id="@+id/shortcut_widget_item_avatar"
android:layout_width="54dp"
@ -12,6 +13,7 @@
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_gravity="start|center_vertical"
android:src="?attr/widgetPreviewImage"
android:gravity="start" />
<RelativeLayout
@ -33,6 +35,7 @@
android:textColor="@color/widget_name"
android:layout_alignParentStart="true"
android:layout_marginEnd="4dp"
android:text="?attr/widgetPreviewTitle"
android:layout_toStartOf="@+id/shortcut_widget_item_time"/>
<TextView android:id="@+id/shortcut_widget_item_time"
@ -41,6 +44,7 @@
android:layout_alignParentEnd="true"
android:layout_marginTop="3dp"
android:textSize="13dp"
android:text="?attr/widgetPreviewTime"
android:textColor="@color/widget_time" />
</RelativeLayout>
@ -65,22 +69,16 @@
android:autoLink="none"
android:textColorLink="@color/widget_text"
android:layout_alignParentStart="true"
android:text="?attr/widgetPreviewContent"
android:layout_toStartOf="@+id/shortcut_widget_item_badge"/>
<TextView android:id="@+id/shortcut_widget_item_badge"
android:layout_width="wrap_content"
android:layout_height="23dp"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:paddingBottom="1dp"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:minWidth="23dp"
android:textSize="13dp"
android:layout_marginStart="4dp"
<TextView
android:id="@+id/shortcut_widget_item_badge"
style="@style/TMessages.AppWidget.Badge"
android:layout_alignParentEnd="true"
android:background="@drawable/widget_counter"
android:textColor="@color/widget_badge" />
android:layout_marginStart="4dp"
android:text="2"
android:visibility="?attr/widgetPreviewDot" />
</RelativeLayout>

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="76dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="148dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="220dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="292dp"
android:background="@drawable/widget_bg"
android:padding="2dp">
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/TMessages.AppWidget.Background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:theme="@style/Theme.TMessages.AppWidget"
tools:ignore="UnusedAttribute">
<include
layout="@layout/shortcut_widget_item"
android:theme="@style/Theme.TMessages.AppWidget.Preview" />
<include
layout="@layout/shortcut_widget_item"
android:theme="@style/Theme.TMessages.AppWidget.Preview2" />
</LinearLayout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2021 Google LLC
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<!-- APP WIDGET -->
<style name="Base.Theme.TMessages.AppWidget" parent="android:Theme.DeviceDefault.DayNight" />
<style name="TMessages.AppWidget.Background" parent="Base.TMessages.AppWidget.Background">
<item name="android:clipToOutline">true</item>
<item name="android:background">@drawable/widget_background</item>
</style>
<style name="TMessages.AppWidget.Badge" parent="Base.TMessages.AppWidget.Badge">
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="app_widget_background_corner_radius">@android:dimen/system_app_widget_background_radius</dimen>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="widgetBackgroundCornerRadius" format="dimension" />
<attr name="widgetPreviewTitle" format="string" />
<attr name="widgetPreviewContent" format="string" />
<attr name="widgetPreviewTime" format="string" />
<attr name="widgetPreviewImage" format="reference" />
<attr name="widgetPreviewDot" format="integer" />
</resources>

View file

@ -130,4 +130,94 @@
<item name="android:windowFullscreen">false</item>
</style>
<!--APP WIDGET-->
<style name="Base.Theme.TMessages.AppWidget" parent="Theme.TMessages"/>
<style name="Theme.TMessages.AppWidget" parent="Base.Theme.TMessages.AppWidget">
<item name="widgetBackgroundCornerRadius">@dimen/app_widget_background_corner_radius</item>
<item name="widgetPreviewTitle"/>
<item name="widgetPreviewContent"/>
<item name="widgetPreviewTime"/>
<item name="widgetPreviewDot">0</item>
<item name="widgetPreviewImage">@null</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview">
<item name="widgetPreviewTitle">Local Weather</item>
<item name="widgetPreviewContent">&#9728; 30°C Sunny,</item>
<item name="widgetPreviewTime">13:00</item>
<item name="widgetPreviewDot">0</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_5</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview2">
<item name="widgetPreviewTitle">Rex</item>
<item name="widgetPreviewContent">It\'s morning in Tokyo &#128526;</item>
<item name="widgetPreviewTime">12:00</item>
<item name="widgetPreviewDot">2</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_7</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview3">
<item name="widgetPreviewTitle">Dolph Ingman</item>
<item name="widgetPreviewContent">&#128517; Sticker</item>
<item name="widgetPreviewTime">11:00</item>
<item name="widgetPreviewDot">2</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_6</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview4">
<item name="widgetPreviewTitle">Doge</item>
<item name="widgetPreviewDot">0</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_1</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview5">
<item name="widgetPreviewTitle">Donald</item>
<item name="widgetPreviewDot">2</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_4</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview6">
<item name="widgetPreviewTitle">Kate</item>
<item name="widgetPreviewDot">2</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_2</item>
</style>
<style name="Theme.TMessages.AppWidget.Preview7">
<item name="widgetPreviewTitle">Nick</item>
<item name="widgetPreviewDot">2</item>
<item name="widgetPreviewImage">@drawable/widget_avatar_3</item>
</style>
<!-- APP WIDGET STYLES-->
<style name="Base.TMessages.AppWidget.Background" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">2dp</item>
</style>
<style name="TMessages.AppWidget.Background" parent="Base.TMessages.AppWidget.Background">
<item name="android:background">@drawable/widget_bg</item>
</style>
<style name="Base.TMessages.AppWidget.Badge" parent="android:Widget">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">23dp</item>
<item name="android:paddingLeft">7dp</item>
<item name="android:paddingRight">7dp</item>
<item name="android:paddingBottom">1dp</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
<item name="android:minWidth">23dp</item>
<item name="android:textSize">13dp</item>
<item name="android:background">@drawable/widget_badge_background</item>
</style>
<style name="TMessages.AppWidget.Badge" parent="Base.TMessages.AppWidget.Badge">
<item name="android:textColor">@color/widget_badge</item>
</style>
</resources>

View file

@ -2,4 +2,5 @@
<resources>
<bool name="isTablet">false</bool>
<dimen name="custom_notification_corner_radius">2dip</dimen>
<dimen name="app_widget_background_corner_radius">16dp</dimen>
</resources>

View file

@ -1,13 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="320dp"
android:minHeight="78dp"
android:minWidth="250dp"
android:minHeight="110dp"
android:minResizeWidth="180dp"
android:minResizeHeight="40dp"
android:targetCellWidth="4"
android:targetCellHeight="2"
android:updatePeriodMillis="3600000"
android:initialLayout="@layout/shortcut_widget_layout_1"
android:initialLayout="@layout/shortcut_widget_layout_2"
android:autoAdvanceViewId="@id/list_view"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:description="@string/EditWidgetChatsInfo"
android:previewImage="@drawable/chats_widget_preview"
android:previewLayout="@layout/shortcut_widget_layout_preview"
android:widgetFeatures="reconfigurable|configuration_optional"
android:configure="org.telegram.ui.ChatsWidgetConfigActivity">
</appwidget-provider>

View file

@ -3,11 +3,18 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="110dp"
android:minHeight="86dp"
android:minResizeHeight="40dp"
android:maxResizeHeight="110dp"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:updatePeriodMillis="3600000"
android:initialLayout="@layout/contacts_widget_layout_2"
android:autoAdvanceViewId="@id/list_view"
android:resizeMode="vertical"
android:widgetCategory="home_screen"
android:description="@string/EditWidgetContactsInfo"
android:previewImage="@drawable/contacts_widget_preview"
android:previewLayout="@layout/contacts_widget_layout_preview"
android:widgetFeatures="reconfigurable|configuration_optional"
android:configure="org.telegram.ui.ContactsWidgetConfigActivity">
</appwidget-provider>